tag:blogger.com,1999:blog-15045980.post-60151821967463601652018-06-26T15:02:00.000-07:002018-06-26T15:04:39.210-07:00Testing on the Toilet: Only Verify Relevant Method Arguments<span id="docs-internal-guid-7e1766f2-3e0c-56eb-ab06-1655721a9901" style="font-family: "times" , "times new roman" , serif;"><span style="font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This article was adapted from a </span><a href="http://googletesting.blogspot.com/2007/01/introducing-testing-on-toilet.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-style: italic; vertical-align: baseline; white-space: pre-wrap;">Google Testing on the Toilet</span></a><span style="font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> (TotT) episode. You can download a </span><a href="https://docs.google.com/document/d/1BxUCm5HuCg2_cq0iSI060iLCSMXzuudb-Ob57MhCJcw/edit" rel="nofollow" style="text-decoration-line: none;"><span style="color: #1155cc; font-style: italic; vertical-align: baseline; white-space: pre-wrap;">printer-friendly version</span></a><span style="font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> of this TotT episode and post it in your office.</span></span><br />
<span style="font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="font-family: Times, Times New Roman, serif; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">By Dillon Bly</span><br />
<span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="font-family: "times" , "times new roman" , serif; vertical-align: baseline; white-space: pre-wrap;">What makes this test fragile?</span><br />
<div style="overflow-x: auto;">
<table class="my-bordered-table" style="width: 613px;"><tbody>
<tr><td style="background-color: #f4cccc; vertical-align: top; width: 607px;"><pre style="background-color: #f4cccc; border: 0px; margin: 0px; padding-bottom: 0px; padding-left: 0px; padding-top: 0px;"><span style="color: black; font-family: "consolas" , "courier new" , "courier" , monospace;">@Test public void <span style="font-weight: bold;">displayGreeting_showSpecialGreetingOnNewYearsDay</span>() {
fakeClock.setTime(<span style="font-weight: bold;">NEW_YEARS_DAY</span>);
fakeUser.setName("<span style="font-weight: bold;">Fake User</span>”);
userGreeter.displayGreeting();
// The test will fail if userGreeter.displayGreeting() didn’t call
// mockUserPrompter.updatePrompt() with these exact arguments.
<span style="font-weight: bold;">verify(mockUserPrompter).updatePrompt(
"Hi Fake User! Happy New Year!", TitleBar.of("2018-01-01"), PromptStyle.NORMAL);</span>
}</span></pre>
</td></tr>
</tbody></table>
</div>
<br />
<span id="docs-internal-guid-bc84817c-3e14-e5cc-a05d-16b057db019f"><span style="font-family: "times" , "times new roman" , serif; vertical-align: baseline; white-space: pre-wrap;">The test specifies exact values for all arguments to </span><span style="color: #0d904f; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: "courier new" , "courier" , monospace;">mockUserPrompter</span></span><span style="font-family: "times" , "times new roman" , serif; vertical-align: baseline; white-space: pre-wrap;">. </span><span style="font-family: "times" , "times new roman" , serif; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"><span style="color: purple;">These arguments may need to be updated when the code under test is changed, even if the changes are unrelated to the behavior being tested</span></span><span style="font-family: "times" , "times new roman" , serif; vertical-align: baseline; white-space: pre-wrap;">. For example, if additional text is added to </span><span style="color: #0d904f; font-family: "times" , "times new roman" , serif; vertical-align: baseline; white-space: pre-wrap;">TitleBar</span><span style="font-family: "times" , "times new roman" , serif; vertical-align: baseline; white-space: pre-wrap;">, every test in the codebase that specifies this argument will need to be updated.</span></span><br />
<span style="font-family: "times" , "times new roman" , serif; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span id="docs-internal-guid-2bb90996-3e17-07d1-2522-8f9508921c42" style="font-family: "times" , "times new roman" , serif;"><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">In addition, </span><span style="font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"><span style="color: purple;">verifying too many arguments makes it difficult to understand what behavior is being tested</span></span><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> since it’s not obvious which arguments are important to the test and which are irrelevant.</span></span><br />
<span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span id="docs-internal-guid-f45a3252-3e17-a749-b17d-2afb4c9bacca" style="font-family: "times" , "times new roman" , serif;"><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline;">Instead, </span><span style="font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline;"><span style="color: purple;">only verify arguments that affect the correctness of the specific behavior being tested</span></span><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline;">. You can use argument matchers (e.g., </span><span style="color: #0d904f; vertical-align: baseline;"><span style="font-family: "courier new" , "courier" , monospace;">any()</span></span><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline;"> and </span><span style="color: #0d904f; vertical-align: baseline;"><span style="font-family: "courier new" , "courier" , monospace;">contains()</span></span><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline;"> in Mockito) to ignore arguments that don't need to be verified:</span></span></span><br />
<div style="overflow-x: auto;">
<table class="my-bordered-table" style="width: 613px;"><tbody>
<tr><td style="background-color: #d9ead3; vertical-align: top; width: 607px;"><pre style="background-color: #d9ead3; border: 0px; color: black; margin: 0px; padding-bottom: 0px; padding-left: 0px; padding-top: 0px;"><span style="font-family: "consolas" , "courier new" , "courier" , monospace;">@Test public void <span style="font-weight: bold;">displayGreeting_showSpecialGreetingOnNewYearsDay</span>() {
fakeClock.setTime(<span style="font-weight: bold;">NEW_YEARS_DAY</span>);
userGreeter.displayGreeting();
<span style="font-weight: bold;">verify(mockUserPrompter).updatePrompt(contains("Happy New Year!"), any(), any()));</span>
}</span></pre>
</td></tr>
</tbody></table>
</div>
<br />
<span id="docs-internal-guid-f315adfc-3e1c-2c4c-701f-353cc666cc03" style="font-family: "times" , "times new roman" , serif;"><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arguments ignored in one test can be verified in other tests. Following this pattern allows us to </span><span style="font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"><span style="color: purple;">verify only one behavior per test</span></span><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, which makes tests more readable and more resilient to change. For example, here is a separate test that we might write:</span></span><br />
<div style="overflow-x: auto;">
<table class="my-bordered-table" style="width: 613px;"><tbody>
<tr><td style="background-color: #d9ead3; vertical-align: top; width: 607px;"><pre style="background-color: #d9ead3; border: 0px; color: black; margin: 0px; padding-bottom: 0px; padding-left: 0px; padding-top: 0px;"><span style="font-family: "consolas" , "courier new" , "courier" , monospace;">@Test public void <span style="font-weight: bold;">displayGreeting_renderUserName</span>() {
fakeUser.setName(“<span style="font-weight: bold;">Fake User</span>”);
userGreeter.displayGreeting();
// Focus on the argument relevant to showing the user's name.
<span style="font-weight: bold;">verify(mockUserPrompter).updatePrompt(contains("Hi Fake User!"), any(), any());</span>
}
</span></pre>
</td></tr>
</tbody></table>
</div>
Google Testing Bloggershttps://www.blogger.com/profile/03153388556673050910noreply@blogger.com0