domingo, noviembre 14, 2010

What Colour is God? Why Can't You Tell Me.

Usually one tend to think about testing as a residual part of development. Nothing further from reality. Testing, so JUnit classes, needs to be treated as "business code". Must follow naming conventions, code must be sectioned, and of course must be readable. For this reason, John Ferguson Smart has its own rules that I would like to summarize and comment:

As John Ferguson Smart told in his entries, there are 5 rules that all JUnit classes must follows, that rules are:

I. Don't say "test", say "should".

JUnit test should pass, but "should pass", maybe there is something wrong in classes that makes test fail, for this reason we are writing off tests. Also, test cases must be validated with requirements, because a requirement is specified as should/shall not with test, same nomenclature is used. Thanks of this improvement, it is easy validating requirements using tests.

Also as Neal Ford suggests each word of your test method name must be separated with '_' character. I find this suggestion so useful because you don't need to use your mind for parsing camel case methods. Of course this only applies to JUnit methods (Yes the only exception between delivery classes and test classes). With this small change your test department will be thankful how fast can validate requirements.

For example the method: testTransfer must be changed to transferShouldDeductSumFromSourceAccountBalance as John Smart suggests, but another change is better, and is changing to: transfer_Should_Deduct_Sum_From_Source_Account_Balance and that's more readable.

II. Don't test classes, test their behavior.

Of course because test cases are related to use cases, tests must validate behavior. This also affects on avoiding testing your classes for the only porpouse of reaching 100% of coverage. 100% of coverage is important, but guarantees nothing, if you don't keep in mind that you must test behavior.

III. Test class names are important too.

Of course when you want to locate where some behavior is tested, it helps the name of your test. Class names must answer the question: When is this behavior applicable? as method names should answer the question: What behavior are we testing?.

What you think is better test class name: TransactionTest or WhenMoneyTransactionIsCommited. Both test names are valid but second one is descriptive about what behavior are you testing.

IV. Structure your tests well.

Test classes are also business classes and for that reason they also have the right to be refactored, kept clean and readable. For that reason is so important to write tests consistently. A really good suggestion is divide each test in three main sections, Given-When-Then. Only with tabs and CR can work perfectly, but you can also use frameworks like JBehave or Easyb.

V. Test are deliverables too.

Tests must be treated as commercial code, not because your client does not see test classes, you can ignore them from static analysis.

3 comentarios:

Anónimo dijo...

I disagree with the nonstandard naming convention of the method names. I don't think that camel case significantly adds to reading comprehension, and certainly not enough to justify breaking from the convention used in the rest of Java.

Secondly, I disagree that you should name your test class "WhenMoneyTransactionIsCommited". A lot of tools i.e. the NetBeans IDE expect that unit tests have the name ClassNameTest, where ClassName is the class under test, and their JUnit support relies on that naming convention. (i.e. to be able to jump back and forth between the tested class and the test).

Otherwise I think it's a good article.

christian posta dijo...

With respect to my following comment, I do not include the readability of test code. All code should be written with the thought that the person taking over your code is a psychopath and knows where you live. Write it so they can read it without much angst.

On to my comment...

Test code need *not* be held to the same level of quality as production code.

In fact, quite the opposite will be true in some cases. The quality of your test code *will need to be* lower than your production code for the purpose of creating the non-happy-path situations.

Of course, if your only test is to test the happy path, then your test code might end up at the same level of quality as your prod code.

But as you push to test your production code's boundaries and invalid contracts, you'll find that your test code isn't the same quality as your prod code: and this is encouraged.

For example, would you ever write the following for a constructor in any prod code?

MyFooClass testClass = new MyFooClass(null, null)

Absolutely not. But for test code, you absolutely should. You should always test the robustness of your code by stressing on the boundaries and by testing that it behaves appropriately during invalid conditions.

To do that, you may end up with low-quality code.

Alex dijo...

Well I accept what you write, but I disagree. I think that what you are understanding unit testing as a test phase in software development (for example TFD). What I am explaining here is something different, I understand testing as a design activity (TDD and BDD), which generates documentation (specs) that will be used by QA and VVT departments. Because of that it is very important to have your test with quality. It is very important that everyone and at any time (1 year ago) you still understand what are you testing and what validates.

Look if I say testAccountTransfer, you don't know what this method test (you are adding money to an account, you are deducting money?¿) but transferShouldDeductSumFromSourceAccountBalance you know exactly what you are testing. Moreover if you class give you an idea of when this happens (WhenUserCheckoutBasketCase) you know that this test are validating that when user checkout basket case, some "money" should be deduct. And because it is readable, you can generate a document showing which specifications are passed and which not. Then QA and VVT department checks with requirement document which requirements are accomplished in current build and can say "hey with this build we are implemented 50% of requirements". I know this is really difficult because all resides that you have a really nice requirements, but any company that don't want to find surprises at the end of a project, should have all requirements clear before starting coding.

And lastly let me make this reflection, if you need to call your tests with "reserved word" test because if not the framework does not work, then change testing framework. With Eclipse 3.6 and JUnit 4.x there is no name restriction.