Core Java

It’s All About Tests – Part 2

This is the second post of the series about testing. In the first part I explained about the mindset we need to have while developing with tests. Or, in better words, developing for testable code. In this part I will cover some techniques for testing approach. The techniques I will describe can be seen as how to transform the mindset into actions.
 
 
 
 
 
 

Techniques

Types Of Tests

Types of tests are layers of what we test. The most obvious one is the unit test. Using JUnit (or TestNG, or any other tool), you will test the behavior of your code. Each test should check one behavior of the class/method under test. Another layer of tests, which usually done by developers, is what I like to call integration tests. This type of test will usually be part of the code (under the test directory). Integration tests may test several classes together. They may test partial flow.

I like to test Spring wiring, verifying that the context file is correct. For example, if I have injected list of beans and the order is important. Testing the wiring can be considered as integration test. Another example would be checking the integration of a DAO class and the class that uses it. Sometimes there are “surprises” in these parts. As a higher degree of tests, you will want to test request and response (REST). If you have GUI, make an automated test suit for that as well.

Automation

Automate your full development cycle. Use CI service, such as Hudson/Jenkins. Add your JUnit, selenium, JMeter, JBehave to your CI environment.

I suggest the following:

  1. CI that checks the SCM for changes and runs whenever there is a change.
  2. Nightly (or every few hours). A slower automation test suit that check more stuff, like integration tests.

The nightly can be slower. If you do continuous deployment, then your setup may be different.

Environment

Have dedicated environment for testing. DB that can be cleared and refilled. If you work on REST service, have a server just for your test and automation environment. If you can, try making it as similar as possible to production environment.

Stub, Mock

There are frameworks for stubbing and mocking. But first understand what it means. There’s a slight difference between stubbing and mocking. Basically they both fake a real object (or interface). You can tell the fake object to behave as you want in certain input. You could also verify that it was called with expected parameters (more about it in next post).

Usage of External Resources

You can fake DB, or you can use some kind of embedded database. Embedded database helps you isolate tests that include DB. Same thing for external services.

Descriptive Tests

  • Add the message parameter.
    assertTrue("Cache pairs is not size 2", cachPairs.size() == 2);

    It has at least two benefits:

    1. The test is more readable
    2. When it fails, the message is clearer

    How many times you couldn’t tell what went wrong because there was no message? The failing test was assertTrue(something), Without the message parameter.

  • Name you tests descriptively. Don’t be afraid to have test-methods with (very) long name. It really helps when the test fails. Don’t name a test something like: public void testFlow(){...}. It doesn’t mean anything.
  • Have naming convention. I like to name my tests: public void whenSomeInput_ThenSomeOutput() {...}. But whatever you like to name your tests, try to follow some convention for all tests.

Test Structure

Try to follow the: Given, When, Then sequence. Given is the part where you create the test environment (create embedded DB, set certain values etc.). It is also the part where you tell your mocks (more about it next post) how to behave. When is the part where you run the tested code. Then is where you check the result using assertions. It’s the part where you verify that methods were called. Or not. If it’s hard to keep an orderly structure, then consider it as test-smell (see previous post).

Unit Tests Should Run Fast

A unit test of class should run 1-5 seconds. Not more. You want the quickest feedback whether something failed. You will also want to run the unit tests as many times as possible. If a test for one class takes around 30-60 seconds, then usually we won’t run it. Running a full test suit on all your project should not take more than a few minutes (more than 5 is too much).

Coverage

Tests should coverage all your production code. Coverage helps spot code which is not tested. If it’s hard to cover some code, for instance due to many code branches (if-else), then again, you have test smell. If you practice TDD, then you automatically have very high coverage.

Important: Do not make code coverage as the goal. Code coverage is a tool. Use it.

TDD

Allow me not to add anything here…

Conclusion

In this post I gave some more ways, more concrete, on how to approach development with tests. In the following post I will give some pointers and tips on how to work with the available tools.

Eyal Golan

Eyal is a professional software engineer and an architect. He is a developer and leader of highly sophisticated systems in different areas, such as networking, security, commerce and more.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button