4 JUnit Strategy for Testing

Pursue convenient JUnit testability. Encourage frequent invocation of IDE test coverage using functionally equivalent services.

Based on our experience with “the Company,”[1] we encourage a JUnit Strategy for Testing (JUST-enough) approach, which seeks to: minimize external dependencies, leverage functionally equivalent services, minimize the use of Mocks except for reluctant collaborators, and encourages running test coverage frequently.

A modern approach to JUnit testing minimizes external dependencies by enabling internal dependencies (or functionally equivalent services). The classic example being the contemporary ability to interact with a database without leaving the Java Virtual Machine (JVM).

Functionally Equivalent services enable test execution using production code semantics without requiring a Java application server. Here are some examples of functionally equivalent services sustainable inside the JVM:

  • CDI container
  • in-memory database
  • JAX-RS RESTful clients/server
  • JPA persistence engine
  • JNDI tree
  • security subsystems

JVM Sketch

This figure shows a JUnit JVM with a portable CDI container, in-memory database and JAX-RS RESTful client.

Test performance typically degrades when exiting the JUnit JVM. The JUST-enough approach seeks to match the historical performance advantage that testing with mock resources has enjoyed. Functionally equivalent services also enable execution without network connectivity, thus mitigating one of the many challenges of globally sourced anywhere/anytime development.

We have observed the continuing tension between the Classical style of TDD and the Mockist style that Martin Fowler described in 2007[2].  We believe that an exuberance for mock testing is a hold-over from an era when many test code operations were required to achieve effective production code coverage. The JUST approach is dogmatically determined to eliminate test code waste (duplication) with patterns demonstrating simpler testability.

So, when does JUST advocate using a Mock resource?  Oleg Shvartsman has provided a wonderful answer to this question by injecting the term “Reluctant Collaborator” into the discussion.  Oleg defines the term as when a resource is:

  • not yet available
  • not yet stable
  • has access policies hindering availability
  • slow to respond
  • unable to generate failure modes on demand
  • otherwise inconvenient to use

We also advocate pursuing creative techniques for indirect testing of production code to minimize duplication.  In the following excerpt (“Uncle Bob”, 2013) discloses when he does not practice TDD:

So, when do I not practice TDD?

I don't write tests for getters and setters. Doing so is usually foolish. Those getters and setters will be indirectly tested by the tests of the other methods; so there's no point in testing them directly.

I don't write tests for member variables. They too will be tested indirectly.  

I don't write tests for one line functions or functions that are obviously trivial. Again, they'll be tested indirectly.

Generally, the more modular the code the greater the opportunities for indirect testing of “trivial” functions.

As mentioned, it is typical for teams committed to TDD to forego direct testing of getter/setter (accessor/mutator) methods in favor of indirect testing. Beginning in 2006, Todd’s[3] team began experimenting with a JUnit extension, TestUtil,[4] to provide direct testing of an entire application with a single line of test code.

Direct testing of getters/setters with an automated approach like TestUtil, enables commensurable code coverage metrics. That is, measurements of code coverage are comparable because they use the same standard.

It appears running JUnit tests with an IDE coverage tool may finally be going mainstream. The 2017 version of Eclipse (Oxygen) comes with code coverage plugin support (EclEmma) out-of-the-box. We strongly advocate using a coverage tool frequently.

Teams with the best of intentions may fall short of their aspirations when delivery pressures mount. Metrics reported on “big visible charts” or “information radiators” help sustain a culture of accountability to those aspirations. When the radiator shows that coverage metrics slip out of the ideal range, this fact is made more difficult to ignore, and encourages the team to refocus.

References

[1] In 2002, Java was adopted as the standard platform for in-house development at a successful large automotive manufacturing enterprise (“the Company”).

[2] Fowler, Martin 2007. Mocks Aren’t Stubs.  http://martinfowler.com/articles/mocksArentStubs.html 

[3] Todd Hall was technical lead and architect for the original 2004 team launching the PED journey.

[4] This refers to Marvin Toll’s open source TestUtil project, circa 2006.

Martin, Robert C. 2013. The Pragmatics of TDD.
http://blog.8thlight.com/uncle-bob/2013/03/06/ThePragmaticsOfTDD.html