I have a class that is used as part of a financial application. The class is bound to a UI form and accepts a handful of values that are then used to calculate financial data. The calculated values are presented as properties on the object. Several of these calculations use other calculations.
For example, CalculationA may return PropertyA + PropertyB. CalculationB returns PropertyC - CalculationA. (This is an extreme over-simplification).
I am trying to write some unit tests to make sure that these calculations are performed correctly and wondering what approach I should be taking.
My first approach was to manually recal开发者_如何学Goculate the expected result in the test method. For example, when testing CalculationB, I populate the test object then set the expected result equal to PropertyC - PropertyA + PropertyB. But since the real object has 25 properties involved, this is quite cumbersome.
On option I thought of is to simply create the test object, populate it with values then write a test that verifies CalculationA equals PropertyA + PropertyB and another test that verifies CalculationB equals PropertyC - CalculationB. The latter assumes that CalculationB is correct, but does that really matter for the purpose of the unit test?
What guidance/suggestions can you make for setting up my tests so they are accurate, reliable and maintainable? What is the best way to ensure that the calculations are correct and that I didn't accidentally set CalculationB = PropertyB - CalculationA, for instance.
Your case sounds equivalent to a spreadsheet, and a spreadsheet is just unusual syntax for code of the form:
f1(f2(a, f3(b)), c);
Where f1-3 are the calculations, and a-c the input properties. The 'chaining' is the fact that the outputs of some functions are used as inputs to others.
This kind of functional calculation code is where unit testing really shines. Testing the assembly as a whole means that a change to the specification of f3 would change the test cases for f2 and f1 in some complicated but meaningless way. This could well result in someone cutting and pasting the calculation result back into the test as the expected result. Which kind of makes the whole exercise a little pointless.
So if a minimal set of test cases is something like:
f1(7, -2) => 23
f2(1, 2) => 7
f3(4) => 5
then you can implement each of those test cases by:
- set all properties to fixed large numbers
- set the input properties to the input for this case
- check the output property
Because point one is shared between all tests, the effort to produce test cases for each calculation is proportional only to the complexity of that specific calculation, not the total number of properties.
精彩评论