I have a class which calculates a date and I'm wondering how best to test this. I've come up with two approaches and wonder about your thoughts on which is 'better' (and of course, any other ingenious ideas you may have).
For example, in my code, if no con开发者_运维百科dition is met then a default date of one year and one month from today is returned.
Approach #1: Duplicate the date calculation logic in the unit test:
DateMidnight expectedDefaultDate = new DateMidnight().plusYears(1).plusMonths(1);
assertEquals(expectedDefaultDate , unit.getExpireDate());
Approach #2: Inject 'today' as a fixed point in time and hard code expected response date:
DateMidnight fixedPointInTime = new DateMidnight(2011, 06, 05);
unit.setToday(fixedPointInTime);
DateMidnight expectedDefaultDate = new DateMidnight(2012, 07, 05);
assertEquals(expectedDefaultDate, unit.getExpireDate());
I'm quite torn over these. I'm not big on code duplication, but the first approach is more clear to me as to what is expected. Which would you use (if any) and why?
IMHO, Unit tests should have the following attributes:
- be repeatable
- test "interesting" cases
In terms of dates, using "today" is bad as it is different each day you run the test. "Interesting" cases for dates usually involve weekends, holidays, end-of-month/year, etc.
One example that has bitten me in the past: date based tests that work until, one day just before an important release you work through the weekend and find lots of tests that (unexpectedly) fail. If you are working through the weekend you are already under lots of stress and really don't need failing tests to add to the "fear, uncertainty and doubt"!
In summary, don't use "today". If you really want to test every date then don't do it day-by-day, instead code for it in the test running a loop out for a date range that extends from a fixed start date to a date beyond the expected lifetime of the system (and then some).
The purpose of unit tests is to find bugs. I suggest you take the approach which you think is the most likely to find an error. Plain duplication of the code, may not find all errors. However, if you change the original code (to make it more efficient for example) the example may no longer be duplicated.
IMHO, The best thing to do is to write it both ways and either could break under different changes.
The second approach is better. The test code should be very simple and stupid, the tested code should be intelligent and complicated. If the test code is too smart, and the test fails, you will never know if the bug is in the tested code or in the test code.
In the second case there isn't only code duplication, there is also data hardcoding. I preffer the first approach.
It seems there are two things to test here:
- The class correctly calculates one month and one year from today
- The returns date of one year and one month from today under certain circumstances.
Clearly, for #1, you need to use hard-coded values. For the latter now you can repeat the code.
Just my thought, though I wonder this is nit-picking.
精彩评论