tags:

views:

86

answers:

4

I'm working on moving as much logic out of a custom control as possible so that it can be unit tested to reduce manual testing burden. I'm having trouble with situations where a method under test produces a complex result; writing a test case that calculates the result would involve writing what is essentially the code under test into the test itself.

For example, I have a GeometryGenerator class that creates a WPF geometry based on the properties of the class. In one configuration, a PathGeometry that consists of an ArcSegment is generated. I can calculate what the arc's properties should be based on the test parameters, but this calculation is identical to the code that I'm trying to test. This seems like it would make the test ineffective; if there's a bug in the calculation there will be a bug in the test, and if the calculation changes in the method it might have to change in the test.

What do I do about this situation? The only approach I've come up with is to hand-calculate the results of my test cases and hard-code these values into the tests. Is this an acceptable approach (it seems like what I'd have done if I were writing the tests before the implementation)?

A: 

A "unit test" should really just be testing a single unit. So ideally you would have seperate unit tests for your GeometryGenerator, another for your PathGeometry class, a third for your ArcSegment, etc.

By testing each of the units seperately, you can gain some sort of confidence about how they will behave when you invoke given operations on them with a given set of inputs (how the GeometryGenerator behaves when a field in ArcSegment is set to 1, vs how it behaves when the same field is set to 0, etc.).

If your unit test starts to look like you are duplicating existing code to test a certain piece of functionality then I'm afraid you are doing unit testing wrong, and that there is an easier and more effective solution out there for you.

matt b
+1  A: 

Hand calculating and hard-coding are bad in production code, but essential to good unit tests.

You generally want to write one test for each "state" of the code. For example, I often write tests with positive input, negative input, and zero input to make sure the code is working as expected.

Jekke
+1  A: 

Typically, I'll make a magic number that self-documents but is hardcoded, like

const int expectedResult = 2*4/someConstant; // perhaps a comment.

The reader of the test can infer what the values are, or you can add extra comments if necessary.

Drew Hoskins
+4  A: 

The only approach I've come up with is to hand-calculate the results of my test cases and hard-code these values into the tests. Is this an acceptable approach (it seems like what I'd have done if I were writing the tests before the implementation)?

Yes, this is typical. For the purpose of unit testing you have to assume that the formula you're using to calculate your results is correct. It's the software implementation that you're testing.

You precompute a few hand-calculated results to make sure you're not using the code under test to generate the test data (a very bad sin in unit testing). Just make sure you document your test cases so you know what the expected values represent and where they came from.

Bill the Lizard