Multiple arrangements/asserts per unit test?
A group of us开发者_如何学JAVA (.NET developers) are talking unit testing. Not any one framework (we've hit on MSpec, NUint, MSTest, RhinoMocks, TypeMock, etc) -- we're just talking generally.
We see lots of syntax that forces a distinct unit test per scenario, but we don't see an avenue to re-using one unit test with various inputs or scenarios. Also, we don't see an avenue to multiple asserts in a given test without an early assert's failure threatening the testing of later asserts (in the same test).
Is there anything like that happening in .NET unit testing (state- or behavior-based) today?
look at [TestCase(params)] in NUnit allows doing the same test with different inputs.
also, for the multiple asserts thing, look at OAPT (One assert per test) runner - which promises to take a test with muliple asserts and run each assert as its own test: http://rauchy.net/oapt/
we don't see an avenue to re-using one unit test with various inputs or scenarios.
Already the "standard" setup / teardown methods help reusing test code a lot. On top of that, I believe many .Net unit test frameworks implement the same or similar features to their Java counterparts JUnit and TestNG, which support e.g. parametrized tests.
Also, we don't see an avenue to multiple asserts in a given test without an early assert's failure threatening the testing of later asserts (in the same test).
In my interpretation, a test method tests a single use case. If there is an assertion failure, that test fails, and there is a good reason to fix it asap. The normal state of unit tests should be 100% success, in which case all assertions in all tests pass. In other words, a failing test should be the exception rather than the norm; and I tend not to worry about exceptional cases too much. If it still worries you, you can always arrange your test methods to contain only a single assertion each.
We see lots of syntax that forces a distinct unit test per scenario, but we don't see an avenue to re-using one unit test with various inputs or scenarios.
Varying input variables is quite common using RowTest in MBUnit or Theories in xUnit.net. Google either one of those and you'll find several examples. Ben Hall has a great post about using Theory in xUnit.net: http://blog.benhall.me.uk/2008/01/introduction-to-xunitnet-extensions.html
Also, we don't see an avenue to multiple asserts in a given test without an early assert's failure threatening the testing of later asserts
Having multiple asserts in a single test is fine (and common). The concept that needs to be followed here is that a single unit test should be testing a specific behavior or single unit of code. If you have 3 asserts in one unit test, and the first one fails, whether the other 2 pass or not at this point is not important (and most test runners will not run the rest of the asserts in a single test after one fails), what is important is the one failing assert.
There are a lot of opinions out there on whether or not there should be more than one behavior / unit of code tested per test. I prefer one behavior per test for many reasons. The most important one being that when one of those tests fails, I or someone else will have to go back and read the test to see exactly what is failing and why. If we have to read through a unit test that is doing more than just testing a single behavior, then we're wasting time. It's also much easier to make sure that you're writing the correct tests for your code when testing in smaller chunks. I highly recommend getting a copy of Roy Osherove's The Art of Unit Testing.
One solution you could do, is to put the scenario in a SetUp function.
In NUnit you could have a method like:
private class1 c1;
[SetUp()]
private void Setup()
{
c1 = new class1{Prop1 = 'A', Prop2= 'B'};
}
Then have two tests:
[Test()]
private void Property1_Is_A
{
Assert.AreEqual('A', c1.Prop1);
}
[Test()]
private void Property2_Is_B
{
Assert.AreEqual('B', c1.Prop2);
}
The SetUp gets called each time before a test is executed. I suppose you could do something similar with a constructor that would get called once.
That said, there are some good arguments against that, in that an individual test should set up everything it needs. But those aren't hard-and-fast rules.
精彩评论