Chapter 8. Smashing All Test Layers

A software development stack that does not include testing, in the age of test-driven development (TDD), is like shooting itself in the foot. A web framework that is involved transversally with the runtime environment should especially enable the developer to assert all phases of his/her work – from core logic to an HTML presentation through business logic.

Thankfully, Play! Framework 2 is a very good web framework. It provides plenty of helpers to test all those layers. Those helpers will be helpful not only in unit testing but also in applicative tests (business) or functional ones (UI, REST, and so on).

Even though Play! 2 can be integrated with either the Java or Scala testing frameworks, in this book we'll focus on Scala testing for both Java and Scala applications. That's because testing is a perfect way to start learning Scala, resulting in the fact that a test code need not be highly efficient by essence and shouldn't include any core logic at all. In short, its implementation is not critical and shouldn't be visible to final users.

A last note before going into much detail, for those who have used the first version of the Play! Framework; at the time writing, the way to execute tests has changed a lot. Indeed, in the first version, we were able to launch tests through a dedicated URL while running the application in DEV mode and we were presented with an HTML page where tests could be run by clicking an item. This feature hasn't been recovered yet in this second version. We'll see in the next sections how things are going now.

In this chapter we will:

  • Start with the easiest tests to write the atomic ones
  • See how to use the test framework that Play! 2 has included, that is, specs2
  • Use the console to run them and interpret the results
  • Perform complex tests that use other components that the application needs such as applicative tests
  • See workflow tests that are meant to test features a web application is supposed to provide to the outside world (client, browsers, and so on)

Testing atomically

A web application is built on several layers, each of them having their own responsibilities, such as storage, transport, or business. That's probably why it's so difficult to test an application like this as a whole.

Indeed, most of the time a unit test, or what could be considered as a unit piece of the software, will require boilerplates or mock-ups to run it.

The perfect example is fetching a user's information using the REST API our application is exposing. This will require us to have a database, an HTTP broker, and so on. But still it should be considered as a unit test. No business logic, no specific requirements, just a GET method using an ID.

That's why in a web application there exist tests that I'm calling atomic. These tests don't require a specific environment to be run and, of course, are the simplest tests – they can be seen as plain unit tests in a utility library, for instance.

A famous testing framework in Scala is specs2. specs2 has an amazing number of features that shall require a full book and, actually, the user guide is already one in itself (http://etorreborre.github.com/specs2/guide/org.specs2.UserGuide.html). However, we'll see some of them in action in the following sections.

The principle that resides within specs2 is the definition of specifications, which are kind-of readable sentences that describe the tests you're performing and allow you to both define unit as well as acceptance tests.

Roughly, a specification is structured as several layers. The first layer defines the goal of the specification. Then it will contain several fragments that include the test code and return a Result class—a specs2 one—such as a standard status (ok, failure, and so on) or a matcher (such as something must be not null).

specs2 also has two different notations for defining tests, which are the unit and the acceptance notations. We'll use the unit one for the rest of the book because it offers the more intuitive DSL.

So let's write an atomic test for our comparison code (back to Chapter 2, Scala – Taking the First Step) between Java and Scala. But let's test the Java implementation only in Scala!

What we'll test are the high-order functions that were created in order to draw some parallelism between Java and Scala. These are gathered in the comparison.Sequence.java file.

The root folder, where the tests files are expected to be in Play! 2, is test, right under the root of the application; that is, sibling to app.

So in order to write our tests, we'll create a folder in tests/atomic and a file named ComparisonTest.scala.

Here is how simple tests would look and how we can run them:

Testing atomically

In the previous screenshot, we can see several tests of the comparison.Sequence functions we've implemented in Chapter 2, Scala – Taking the First Step. We have at least one test by function.

It should be worth reviewing it a bit now before seeing them run.

First of all, a specification has to extend the org.specs2.mutable.Specification class, which expects in its body the definition of at least one specification. Such a definition must start with a string message declaring the topic of the specification; in this case, we test Sequence. This message will be used to give an intuitive print of the tests in the console.

Note

Some would wonder, how is that possible? Actually, in Scala, monkey patching is available using lexically scoped implicit conversions. Thus, specs2 has patched the String class with new composition operators.

Having defined the topic, we have to declare what this topic should respect. That's the role of the following fragments that have been introduced using the should method on the "topic". In most cases, a fragment is some information separated by the in method, a human-readable description of the message (one line) and the testing block. Looking at the sample, we can see that those couples can be chained in order to create several fragments to be checked all in one row.

So far so good, but what are those blocks defining how we can create some assertions? For this, we need to review the testing blocks. Let's do it one by one, since they're using different matchers . A matcher in specs2 can be seen as assertThat in JUnit so that it can construct a complex check but also be composed. There are plenty of different matchers provided by the specs2 framework and others provided by the Play! Framework 2 as well (we'll see them in the following sections). There are five fragments being defined in the sample shown in the previous screenshot. As mentioned before, each of them return Results (of which matcher is a subtype).

The key point is the must method that can be used on any computation. This method's role is to take a predicate to assert the correctness of the computed value.

Note

This is possible using the monkey patching trick we saw previously (for String). For your information, Scala has a dedicated term for this technique called pimp-my-library .

OK, this time we can see how to do some checks. The first check for the even function, which returns all even numbers in the Sequence list, is asserting that the resulting list will exactly match the expected one. For that we take the result of the computation and say that it must be identical to the provided expected List of 2 and 4. An equality comparison is done using the be_== operator. You guessed it; there are other such comparators such as be_<= and so on.

Note

We imported the Java conversion methods in the beginning of the class, so we're able to ask toList on the java.util.List that returns the even function.

Moving to the second test (fragment), we checked that the result of squaring each element in the list is equal to the provided List of squares. This is cool, but hardcoded. Even if the comparison code is using the same List instance all the time, in the real world those functions must work on any List instance. So we would like to assert that the function is respecting its contract ; for instance, the even function execution must always return a List that is composed of even numbers only. This is shown in the third test wherein we asked the result to have all elements respecting the provided pattern. In this case, the pattern is simply the item itself (which is inferred to be an Int), but it must be a multiple of 2.

The fourth test is a bit more advanced (OK, not that much) because its result involves a conjunction of two assertions, one of them being a simple Boolean check using the beTrue operator. The second is the negation (using not) of an unsafe result (that throws a NoSuchElementException). For this last point, it'd be worth noting that None that is extending Option<A>, the result type of find, is throwing an exception when trying to get the underlying value.

And finally, the last check is simply asserting a false result.

That was easy. Our tests have been written; let's see now how we can run them.

Running our atomic tests

In this second version of the Play! Framework, the test environment configuration and their runs have been delegated to the build tool SBT. Hence, to run the tests we must enter the play console, and rather than launching the run command, we can execute the test command. This command has the responsibility to compile everything, including the sources in the test folder, and then run all tests in there.

Here is the result for our tests.

Running our atomic tests

Wow, what are those errors, crosses, and scary messages shown there? Actually, that's why tests are written, to discover mistakes. And this is the result we'll get when mistakes are found. The result of the tests shown here is telling us that four tests out of five were successful, so one has failed. Finding which one is pretty easy since it's the only one in the tests summary that has an orange cross whereas the others have beautiful green plus signs.

Before looking at the failure, we shall take a look at what's being printed by the framework on the console.

Indeed, since we respected the structure and the text content, for which we've been helped by the DSL (Domain Specific Language) itself (using methods named should, in, must, and so on), we can now take the output and read it from the top; line by line it provides the following output:

  • Sequence should return even integers using even
  • Sequence contains all squares using squareSeq

These sentences simply describe what the test will do.

Back to the test that has failed; we notice that the framework is literally telling us that the result list (printed first) isn't equal to the expected list (printed later).

Then it prints the list again with their role in the test and where they differ.

So it seems our squareSeq function is buggy (it's true); here it is:

Running our atomic tests

See? Indeed, rather than computing the square of each element, we computed the nth power of two of element, which can be checked easily since the test's result has printed the actual List containing values such as 1 (20), 2 (21), 4 (22), 8 (23), 16 (24), and 32 (25).

The fix is rather trivial; just swapping the arguments will do the trick. After that change, running the tests again will result in the following screenshot:

Running our atomic tests

No more red!

That was a lot of fun, but atomic tests are not the only tests we need while creating a web application. Most of the time actually, they're in the minority. Because of the architecture of a web application, we mostly need tests that involve the server itself, or at least a part of it.

In the Play! Framework 2, the main component at runtime is the Application singleton itself, which is a piece of software that can do everything unless it is working as an HTTP server.

Nevertheless, this is very common because we'll be able to test artifacts such as controllers.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset