Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm trying to build up some test cases, and have read that you should try and limit the number of assertions per test case.

So my question is, what is the best way to go about testing a function w/ multiple inputs. For example, I have a function that parses a string from the user and returns the number of minutes. The string can be in the form "5w6h2d1m", where w, h, d, m correspond to the number of weeks, hours, days, and minutes.

If I wanted to follow the '1 assertion per test rule' I'd have to make multiple tests for each variation of input? That seems silly so instead I just have something like:

self.assertEqual(parse_date('5m'), 5)
self.assertEqual(parse_date('5h'), 300)
self.assertEqual(parse_date('5d') ,7200)
self.assertEqual(parse_date('1d4h20m'), 1700)

In the one test case. Is there a better way?

share|improve this question
    
The best way to do so is using parameters (some framework support this feature, all frameworks should). This way you are testing a single behaviour but taking into account many test cases and still can see what parameter values caused an error if an error occurs –  Kemoda Nov 21 '12 at 15:37
add comment

4 Answers

Purists would say that assertions for different values of input should be put in separate test methods within the test class. One reason for this is that, depending on your testing UI, it's often easier to distinguish between individual test failures than between individual assertions, which might lead you to identify the source of failure more quickly.

When testing with JUnit we can get around this by using the version of assert* methods with an initial String argument to differentiate one assertion from another within the same test method.

self.assertEqual("just minutes", parse_date('5m'), 5)
self.assertEqual("just hours", parse_date('5h'), 300)
self.assertEqual("just days", ('5d') ,7200)
self.assertEqual("days, hours, minutes", parse_date('1d4h20m'), 1700)
share|improve this answer
add comment

Yeah, make multiple tests for each variation of input.

The main goal of the one assertion per test guideline is to have it (ideally) that one error leads to one test failure and vice versa so that you know exactly what failed. Then you can work with one very precise test to debug the root cause and verify. You can break this with one assert, and you can be okay with multiple asserts. In this particular scenario, I would have a test for each suffix and a few combinations of ordering.

Hopefully it is clear why isolating tests is a benefit: you waste less time debugging when something does go wrong. Now, if you're really sure that the test is unlikely to fail, and that overhead of hunting through the test is small, then maybe it makes sense to just test them all at once to save implementation time.

But history has shown that saving a little time writing code at the expense of reading/using code is never worth it. Hence the guideline.

share|improve this answer
add comment

A more pragmatic way to view the one assert per test "rule", is to have your asserts in a single test cover a single concept.

This way you are still testing a single concept in a single test. In your case, whether your input string is correctly parsed in a single date.

You should exercise your judgement on a case by case basis to check if you are better off testing a single concept with multiple asserts or having a single assert in a many tests.

Go for the option that makes for clearer tests, less repetition while still having your tests be able to highlight different points of failures in your method. You want it to be clear when a test fails exactly what happened rather than have to debug your test to find out what went wrong.

share|improve this answer
add comment

It depends very much on your testing library. In the C# library NUnit you can doing something like:

[TestCase('5m', 5)]
[TestCase('5h', 300)]
[TestCase('5d', 7200)]
[TestCase('1d4h20m', 1700)]
public void ParseDateTest(inputString, expectedMinutes)
{
    Assert.That(parse_date(inputString), Is.EqualTo(expectedMinutes));
}
share|improve this answer
    
In java with testng you have @DataProvider methods –  Kemoda Nov 21 '12 at 15:41
    
that's the best solution IMHO. in almost every language you can parameterize your tests. for java: @Parameterized, JunitParams, Zohhak –  piotrek Dec 8 '12 at 16:38
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.