views:

341

answers:

5

I need a unit test to make sure I am accumulating vacation hours properly. But vacation hours accumulate according to a business rule, if the rule changes, then the unit test breaks.

Is this acceptable? Should I expose the rule through a method and then call that method from both my code and my test to ensure that the unit test isn't so fragile?

My question is: What is the right way to unit test business rules that may change?

+3  A: 

I have a similar setup - however my business rules are compiled but have configurable options (yours may differ). When a business rule changes a core way in which it operates, my unit tests break. This is actually expected - and good! It means that I can isolate any unexpected ripples throughout my system and update the tests to match the changes.

If your rules are external (some sort of script language or database sproc) then you will need to wrap them in an integration test and wire up your integration tests for automated execution. While no longer a unit test, integration tests are fairly important as well, and will help you in the same way as unit tests to prevent unexpected ripples due to a business rule change.

cfeduke
A: 

It sounds correct that the test fails if the rules are changed - that is to be expected.

You can make it easier to maintain the test in the future if you use a data fixture instead of hardcoded values in the test itself. For example, if your method should return foo, you can have that in the fixture. When you change the business logic, you simply change the fixture and you won't have to go through the unit test itself.

Of course, this highly depends on the type of logic you are testing, and may not always be applicable.

Jani Hartikainen
+4  A: 

Your tests should ensure that the code properly obeys the business rule. Therefore, I wouldn't write tests that go around the business rule or rely on the business rule code itself. Rather, when the business rule changes, I would first change the test to reflect the new business rule, then when my code no longer passes the test, go and fix the code so that it passes the test.

What you don't want to happen is to write your test so that when you change how the same business rule is applied, that your test breaks. That's easier said than done, but essentially what you want to test is the minimum required to implement the rule without dictating too narrowly how the code is implemented. If the outcome of the rule is different, though, then you should be changing the test first, then the code to match it.

You also don't want the test to be coupled to specific data, either. Say when doing a tax calculation, your test shouldn't be written to assume that the class under test uses 5% as the tax. Instead, you should write your test so that it supplies the tax percentage, and then checks that the calculation is done correctly. Presumably, you'll have a range of values to test to make sure that out of range values are caught as well. One result of this is that you'll have a better design as this will help you to avoid hard-coded values and make your production code more flexible to changes in data.

tvanfosson
+1  A: 

It sounds like you have business rules, and then you have clients of those business rules. If those two can vary independently, it would be wise to design your API accordingly.

As presented, your question sounds like it can be solved with appropriate use of the Strategy pattern. The Strategy represents your business rules, so you can unit test those in a pure context without worrying about the client.

When the business rule changes, it may make more sense to simply leave the old Strategy as is (in case you need it again later on), and write (and unit test) a completely new Strategy that represents the new business rule.

When you are completely done with the new Strategy, you can replace the Strategy in the client.

When unit testing the client, you should do that against a Test Double Strategy (like a Mock or Stub) to verify that the client interacts correctly with the Strategy without being dependent on any particular Strategy implementation.

In this way, you get clean separation of concerns and you keep your unit tests maintainable. You also obey the Open/Closed Principle.

Mark Seemann
A: 

This post shows how to effectively unit test BizTalk Business Rules :

http://whiteboardworks.com/2010/03/unit-testing-biztalk-business-rule-engine

I hope that helps. Regards.

Bruno Spinelli