[Example] Top-down ATDD/TDD with acceptance tests covering third party API

What is ATDD?

ATDD is Acceptance Test Driven Development. In one short sentence: we start with an acceptance test that describes the functionality we want to implement from users point of view. Acceptance tests ideally should be “black box” tests. They should talk to the application only through the interfaces it exposes.

The story

We will implement a webservice that adds numbers and returns the result. Since we want to do the simplest thing possible we will use the Servlet API.

The acceptance test

We start with an acceptance test. It is an example expected behaviour of the system from users point of view. So in this case the user sends a request to our webservice to add two numbers and expects a result in return. Please notice we use Jetty embeded server to startup the application (the Application class and its start and stop methods):

We run the test. Since we don’t have any web app under that url we will get 404 NotFound response instead of 200 OK.
So we add a src/main/webapp directory with a web.xml file. That web.xml file should define a servlet so that we get a 200 response.

We create the servlet class as well:

We run the test. Now we get assertion error “Expected: ‘7’ Actual: ” “. So finally we can proceed to a unit test for our CalculatorServlet!

Start with a test:

Notice that we specyfy that the servlet class will be just an adapter. It extracts data from request, sends message to calculator and then stores the result in response. It does not do any calculations.
In this adapter we mock third party interfaces. The assumptions we made while mocking the method calls are verified in the end-to-end/acceptance test.

Notice that the tests uses “OPERANDS” constant that is defined in the production code. This is because the acceptance tests already test the paramater name. We do not want to have many test failed with the same reason. So we reduce the duplication in this case. Now the “operands” keyword is in the production class and in the acceptance test only.

No we can write the production code:

We run the unit test and it passes. But when we run the acceptance test it fails with RuntimeException on Calculator.add(). So we start with a test for it:

The test fails, so we implement the production code:

Now if we run the unit and acceptace test, ALL PASS!

Conclusions

We started with a black box acceptance test. We continued implementing the application parts only when we had a failing test with a clear error/assertion message. The third party API calls we mock in unit tests are testes also on acceptance level.

If you wish to get more from ATDD please take a look at acceptance test frameworks. There are many of them on the web. Recently I described one of them. Using those frameworks can save a lot of your time.

Please notice I was using totallylazy while implementing list operations. It is a functional library with lazy loading (cool math stuff, infinite sequences, fluent interface, …). For further information please look at totallylazy home page.

Please comment and subscribe to RSS! 🙂

How NOT to test drive time dependant functionalities

Recommended reading before you read this article: Fest assertions, Testing time dependant functionalities .

Do NOT do this!

I would like to present an example of an attempt to test time dependant functionality in a not very nice in my opinion way. Please see testing time dependant functionalities for the recommended way.

Below I present two very similar ways of trying to test drive time dependant functionalities. Please remember that the recommended way it to introduce a clock class.

Approach by extending Fest (DO NOT DO THIS)

Approach by extending Hamcrest (DO NOT DO THIS)

Why avoid this approach?

Think about it. Is “is within one second” actually what you are looking for? Probably not. You are looking for “is now”.
The other argument is that is reduces readability.

JUnit vs Fest by example

I assume you know what a Junit assertion is (assertEquals, assertSame, …). Fest assertions is a mini framework that increases readability of our assertions. Some people still use Hamcrest, but it has many disadvantages when you compare it to fest. (I was using Hamcrest for 6 months, then switched to Fest. Now I use Hamcrest only when I have to. For example when I work on an old codebase, etc.)

Please find a simple and quick comparison of pure Junit asserions and Fest assertions below.

Junit

Fest

The most important things I would say about Fest is:

  1. you don’t have to think about the order of parameters (which one is expected, which one is the actual one)
  2. is has a fluent interface, eg. assertThat(obj).hasSomething(a).hasSomethingElse(b).doesNotContain(b)
  3. when you use it for some time you realize that hamcrest and pure junit offer very poor usability
  4. the assertions are a lot more readable then junit and hamcrest ones