views:

157

answers:

8

I know that this is subjective, but I'd like to follow the most common practice. Do you normally create one test method for each class method and stuff it with multiple assertions, or do you create one test method per assertion?

For example, if I am testing a bank account's withdraw method, and I want make sure that an exception is thrown if the user tries to overdraw the account or withdraw a negative amount, should I create testOverdaw and testNegativeWithdrawal, or would I just combine those two assertions in a method called testWithdraw?

+2  A: 

Make multiple test methods; do not combine them into one. Each of your test methods should test one behavior of the method. As you are saying, testing with a negative balance is a different behavior then testing with a positive balance. So, that would be two tests.

You want to do it this way so that when a test fails, you are not stuck trying to figure out which part in that test failed.

Brad
Won't most test runners print out a line number so you can tell which assertion failed?
cbp
Yes but do you want to figure out the reason for the failure from the test name or trawling through source code for a line number that may or may not have changed since the test was run?
cletus
This is a non sequitur (or else you aren't using Visual Studio). You can just click the error to go right to the line of code if you are using either nUnit or MSTest from within Visual Studio.
Mark Brittingham
One other note: I used TestDriven.net to integration nUnit with Visual Studio (http://www.testdriven.net). I do use MSTest now.
Mark Brittingham
I can't imagine this really occurring very often in a small-to-medium sized project. 90% of the test runs are being run through the IDE. In larger teams and projects I could see how this could pop up more often.
cbp
@cbp, why do you insist on going against good practice? Read the replies of other people here and understand that it is a bad idea to test multiple behaviors in one method just like it is bad practice to write a function with multiple behaviors.
Brad
@Brad From experience - because I've been working with unit testing for a few years in a small team and the problem as you state it simply doesn't occur. From my test runner I can get a line number, click on a link and jump straight to the line that caused the failure.
cbp
Btw I'm not arguing that you should be testing significantly different behaviours from one test - just that sometimes its OK to have more than one assertion. For example, something like this would be OK in my books - check that one item is returned and that it is true: Assert.That(result.Count, Is.EqualTo(1)); Assert.That(result[0], Is.True));
cbp
You should have been more clear about that from the beginning. At least I was under the assumption that you were advocating for many many assertions in one big test method! lol
Brad
+2  A: 

Personally I would create one test for each assertion otherwise you have to dig to find the reason for the failure rather than it being obvious from the test name.

If you have to write a few lines of code to set up a test and don't want to duplicate that then depending on your language and test framework you should be able to create a set of tests where each test will execute a block of code before it runs.

cletus
+1 ...for balance
Paul
+1  A: 

I would recommend having one test method per assertion, or rather per a expected behavior. This allows to localize the erroneous code much faster, if any test fails.

notnoop
+1  A: 

I would make those two seperate assertions.

The first represents a valid operation that would happen if a user was using the account regularly, the second would represent a case where data sanitizing was not done, or not properly done.

You want separate test cases so that you can logically implement the test cases as needed, especially in regression scenarios where running all tests can be prohibitively expensive.

GrayWizardx
+2  A: 

One way to do it is have one separate method for each different scenario or setup. In your case you'd probably want one scenario where there is sufficient funds, and one scenario where there is insufficient funds. And assert that in the first one everything works, and in the second one the same operations won't work.

Tor Valamo
+6  A: 

Think of it this way: each test should stand on its own and exercise a relatively discrete set of functionality. If you want to assert whether three things are true about some method that you have created, then you should create a test that includes those three things.

Thus, I have to strongly disagree with the others who have answered. Arbitrarily limiting yourself to one assertion per test will do nothing for you except make your testing unwieldy and tedious. Ultimately it may put you off testing altogether - which would certainly be a shame: bad for your project and career.

Now, that does not mean you have license to write large, unwieldy or multi-purpose testing routines. Indeed, I don't think I've ever written one that is more than 20 lines or so.

As far as knowing which assertion fails when there are several in one function, you will note that both nUnit and MSTest give you both a description and a link when an assertion fails that will take you right to the offending line (nUnit will require an integration tool such as TestDriven.net). This makes figuring out the failure point trivial. Both will also stop on the first failure in a function and both give you the ability to do a debug walkthrough as well.

Mark Brittingham
I agree with most of this but I see one drawback from this approach. If you are doing three assertions for testing three different scenarios, and while running your tests, the first one fails. What about the other two assertions? You don't know if they would have succeeded or failed. Have you broken your three scenarios or only one or two? Any thoughs?
joerage
Good question. First, remember that all assertions in a test should be related. If one fails, it may well have implications for the others. Thus, I'd have to fix the first before being certain of the others anyway.Second, in my style of work, failed tests are cause for immediate repair. So I'm not really worried about the other two until I get that first one fixed. That is, I'll be fixing and testing on that function in a tight loop until all functionality is verified. So, if the others fail, I might fix them by fixing the first. If they don't fail, the retest will tell me immediately.
Mark Brittingham
@joerage Why not just fix the problem, rerun the test and see if the other assertions fail?
cbp
+1  A: 

testOverdraw and testNegativeWithdrawal are two separate behaviors. They shall be tested separately.

A good rule of thumb is to have only one action on the method under test in one unit test (not counting setup and assertions).

philippe
A: 

From the NUnit documentation: "If an assertion fails, the method call does not return and an error is reported. If a test contains multiple assertions, any that follow the one that failed will not be executed. For this reason, it's usually best to try for one assertion per test."

http://www.nunit.org/index.php?p=assertions&r=2.4.6

However, nothing forces you to follow best practices. If it isn't worth your time and effort for this particular project to have 100% granular tests, where one bug means exactly one test failure (and vice-versa), then don't do it. Ultimately it is a tool for you to use at the best cost/benefit balance that you can. That balance depends on a lot of variables that are specific to your scenario, and specific to each project.

Merlyn Morgan-Graham