Test cases do all the work through helper method -- bad practice? - Software Engineering Stack Exchangemost recent 30 from softwareengineering.stackexchange.com2019-09-15T11:27:44Zhttps://softwareengineering.stackexchange.com/feeds/question/312228https://creativecommons.org/licenses/by-sa/4.0/rdfhttps://softwareengineering.stackexchange.com/q/3122287Test cases do all the work through helper method -- bad practice?Attiliohttps://softwareengineering.stackexchange.com/users/2197492016-03-09T18:16:38Z2016-03-13T20:34:22Z
<p>Consider a test suite like this:</p>
<pre><code>public class MyTestSuite {
@Test
public void test_something() {
testHelperMethod("value11", "value12", "value13");
}
@Test
public void test_something_else_meaningful_name() {
testHelperMethod("othervalue21", "othervalue22", "othervalue23");
}
// ...
private void testHelperMethod(String value1, String value2, String value3) {
// set up part (independent of value1, value2, value3)
// action part (dependent on values)
// assertion part (dependent on values)
// tear down part (independent of values)
}
}
</code></pre>
<p>In other words, all the test cases are executed via a single, parametrized helper method, which is structured according to the arrange-act-assert schema. The test cases just call this method with various parameters, according to what exactly needs to be tested.</p>
<p><strong>Question</strong>: what is the disadvantage, if any, of structuring the tests like this, and does this (anti?)-pattern have a common name?</p>
<p><strong>Remarks</strong></p>
<ol>
<li><p>I tried to Google for it for a long time, including <a href="https://stackoverflow.com/questions/333682/unit-testing-anti-patterns-catalogue?page=2&amp;tab=active#tab-top">on SO</a> and
on the <a href="http://blog.james-carr.org/2006/11/03/tdd-anti-patterns/" rel="nofollow noreferrer">blog</a>, but could not find anything useful till now.</p></li>
<li><p>This <a href="https://softwareengineering.stackexchange.com/questions/115050/how-do-i-convince-some-one-that-test-should-do-assertion-not-assertions-and-no">question</a> is the closest I found, but the answers there address other aspects/problems, namely:</p>
<ul>
<li>assertions/setup code intermixed (not the case here, as all
assertions are at the end of the helper method) </li>
<li>more assertions per test (also the case in my example, but I think this is an unrelated issue)</li>
<li>responsibility of helper method is not clear: I think in my
case it <strong>is</strong> clear, just it is different from the 'traditional' one</li>
</ul></li>
<li><p>To be more precise, the assertion part in <code>testHelperMethod</code> is also a separate utility method (called with many-many parameters), but I guess that does not matter much for the question. (I.e.: why is it bad practice to delegate testing to helper methods, if at all?)</p></li>
<li><p>In case this matters, this is an integration test, but I suspect that the answer would be the same for unit-tests as well.</p></li>
</ol>
<p><strong>EDIT</strong>: Changed the names of the test cases to avoid confusion (Previously, they were called <code>test1</code>, <code>test2</code>. In fact, the tests in the project in questions do have meaningful names, I had just made this simplification myself.)</p>
https://softwareengineering.stackexchange.com/questions/312228/-/312235#3122351Answer by Kilian Foth for Test cases do all the work through helper method -- bad practice?Kilian Fothhttps://softwareengineering.stackexchange.com/users/74222016-03-09T18:59:45Z2016-03-09T18:59:45Z<p>There is nothing wrong with structuring your test code as well as your business code. The point of a test suite is that it expresses clearly how the tested code is supposed to behave, and that it signals a failure if it doesn't. With judicious refactoring and well-chosen names in your test code, you can serve this goal <em>better</em> than with cut-and-paste drudgery. </p>
<p>(However, Matthew is quite right: set-up and tear-down code that is common to <strong>all</strong> tests belongs into the framework's special methods, not into your custom subroutines.)</p>
https://softwareengineering.stackexchange.com/questions/312228/-/312291#3122910Answer by Matthew Walton for Test cases do all the work through helper method -- bad practice?Matthew Waltonhttps://softwareengineering.stackexchange.com/users/497482016-03-10T08:42:02Z2016-03-10T08:42:02Z<p>You should absolutely factor out common code in unit tests. Messy and badly-structured unit test code just leads to tests which are difficult to understand and difficult to maintain, no matter how beautiful the code they're testing is.</p>
<p>That said, in this particular case if you were using the .NET test framework NUnit this wouldn't be necessary at all - you'd turn the helper into a test method and use the <code>TestCase</code> attribute to get the framework to call it multiple times with different parameter sets. I'd be surprised if there wasn't something equivalent available for Java and other languages.</p>
<p>So do structure unit tests well, but also make sure you've learned the capabilities of the test framework because it might be able to help you.</p>
https://softwareengineering.stackexchange.com/questions/312228/-/312312#3123123Answer by Marjan Venema for Test cases do all the work through helper method -- bad practice?Marjan Venemahttps://softwareengineering.stackexchange.com/users/13242016-03-10T11:55:53Z2016-03-10T11:55:53Z<p>As others have already stated: nothing wrong with breaking out a separate method to avoid duplication.</p>
<p>However, as others have also stated: you do want each individual test to clearly indicate what it is setting up and what it is asserting.</p>
<p>Test names will help with that enormously and I assume your actual code has more meaningful names than <code>Test1</code> and <code>Test2</code>.</p>
<p>To make the code of the individual tests more "intelligible" - ie make it clearer what each test is doing just by reading the code of that test, you can break up your helper method into its obvious parts.</p>
<p>Yes, it will "duplicate" what would otherwise be confined to the single helper as you will now have a number of calls in each test when you could do it with one, but it allows you to give more meaningful names to each helper method.</p>
<pre><code>// Arrange
someHelper = MakeSomeDependency(arg1, arg2, arg3);
sut = MakeSomeObjectUnderTest(someHelper);
// Act
sut.DoSomething();
// Assert
AssertCommonAsserts(sut, expectedvalue1, expectedvalue2);
Assert.AreEqual(sut.SomeProperty, expectedValue);
</code></pre>
<p>Note: I am not a fan of multiple asserts in a single test, but there are cases when a single "fact" can only be checked by multiple asserts and I can also think of a number of scenarios in which having some "guard" asserts before the actual "fact" being asserted can help in debugging failures.</p>
<p>If you use a language that supports named parameters, you can make your tests even more intelligible by using that feature so the method call doesn't just convey the values used, but also what those values are used for.</p>
<pre><code>// Arrange
someHelper = MakeSomeDependency(
knownNames: arg1,
unknownNames: arg2,
lookingFor: arg3);
sut = MakeSomeObjectUnderTest(someHelper);
// Act
sut.DoSomething();
// Assert
AssertCommonAsserts(
objectUnderTest: sut,
numberOfItemsFound: expectedvalue1,
nameOfItemFound: expectedvalue2);
Assert.AreEqual(sut.SomeProperty, expectedValue);
</code></pre>
https://softwareengineering.stackexchange.com/questions/312228/-/312620#3126200Answer by thepacker for Test cases do all the work through helper method -- bad practice?thepackerhttps://softwareengineering.stackexchange.com/users/1610042016-03-13T20:34:22Z2016-03-13T20:34:22Z<p>You should consider using a parameterized Runner using a DataProvider for all valid input for your particular test cases, instead of your upper aproach. I use helper methods only to increase readability of tests, if they have a complex setup in the test and which would clutter the arrange part of the test.</p>
<p>What it could look like is:</p>
<pre><code>@RunWith( DataProviderRunner.class )
public class YourClassTest {
@Test
@DataProvider( value = { "value11|value12|value13","value21|value22|value23" },
trimValues = true, splitBy = "\\|" )
public void test_something(String value1, String value2, String value3) {
// action part (dependent on values)
// assertion part (dependent on values)
}
@Before
public void independendSetup() {
// set up part (independent of value1, value2, value3)
}
@After
public void independendtearDown() {
// tear down part (independent of values)
}
}
</code></pre>