Contribute to help us improve!

Are there edge cases or problems that we didn't consider? Is there a technical pitfall that we should add? Did we miss a comma in a sentence?

If you have any input for us, we would love to hear from you and appreciate every contribution. Our goal is to learn from projects for projects such that nobody has to reinvent the wheel.

Let's collect our experiences together to make room to explore the novel!

To contribute click on Contribute to this page on the toolbar.

Test Automation

Developing in an agile way has become normal in our projects. Having a quality assured deliverable product at any time or at least at the end of each sprint can only be achieved with efficient test automation. This section provides good practices for this.

Understand test automation dimensions

There is not one set of rules and tools for test automation. Typically, there are the following integration levels with different test scopes:

  • Unit-Tests: test for smallest testable unit; not more than one class; all other classes mocked; especially no access to database.

  • (Unit-Integration-Tests): closely related units are tested together; outside scope mocked; no access to database; often not considered as an extra level, but as part of Unit-Tests.

  • Subsystem-Tests (aka API-Tests or Service-Tests): test for a fully integrated deployable part of the system; usually with database (can be in memory); API calls not via Java methods, but from the outside, e.g. REST; external systems or system parts are mocked.

  • System-Tests (aka UI-Tests): tests for a fully integrated system with backend and frontend; usually with database; external systems are mocked.

  • System-Integration-Tests: tests for multiple fully integrated systems together; from a technical perspective they can be treated like System Tests, only the organization of such tests is much more complicated.

In addition to the integration levels test automation can be done for different quality characteristics of a software product (e.g. functionality, performance, security, …​).

General good practices

Utilize different integration levels

  • Apply the test pyramid for test intensity on different levels, i.e. aim for many Unit-Tests for fast feedback and only few UI-Tests to ensure integration.

  • For microservices the complexity is often in the external communication rather than in the internal logic. In these situations consider a test honeycomb like proposed by Spotify

  • Use Unit-Tests and Unit-Integration-Tests for business-logic, complex mappings and exceptional flows that need mocking.

  • Adapters and other coordinators (i.e., code that mainly maps and routes) can be tested implicitly in Subsystem-Tests.

Apply FIRST principle

Implement FIRST tests (a must for Unit-Tests):

  • Fast

  • Isolated (test must be independent of each other)

  • Repeatable

  • Self-Validating (no test without assertion)

  • Thorough (cover not only the happy path)

Stating the obvious, because reality is often different

  • Decide what to test before coding. Tests should have a clear goal that should also be documented.

  • Test code shall NOT be seen as second class code. Consider design, architecture and code-style also for your test code.

  • Use continuous integration and establish that the entire team wants to have clean builds and running tests.

Design for testability

Architecture should support testability. If testing feels hard, it is worth to reconsider your design. Some general rules:

  • Take separation of concerns seriously. If your business logic is well structured and free of technical code, it can be tested easily.

  • Apply information hiding. If classes exchange huge data structures even if only few attributes are needed, your test complexity explodes.

  • Use dependency injection. This allows mocking of external functionality.