9 Writing larger tests

 

This chapter covers

  • Deciding when to write a larger test
  • Engineering reliable integration and system tests

Most of the code we tested in previous chapters could be tested via unit tests. When that was not possible because, say, the class depended on something else, we used stubs and mocks to replace the dependency, and we still wrote a unit test. As I said when we discussed the testing pyramid in chapter 1, I favor unit tests as much as possible when testing business rules.

But not everything in our systems can (or should) be tested via unit tests. Writing unit tests for some pieces of code is a waste of time. Forcing yourself to write unit tests for them would result in test suites that are not good enough to find bugs, are hard to write, or are flaky and break when you make small changes in the code.

This chapter discusses how to identify which parts of the system should be tested with integration or system tests. Then I will illustrate how I write these tests for three common situations: (1) components (or sets of classes) that should be exercised together, because otherwise, the test suite would be too weak; (2) components that communicate with external infrastructure, such as classes that communicate with databases and are full of SQL queries; and (3) the entire system, end to end.

9.1 When to use larger tests

I see two situations where you should use a larger test:

9.1.1 Testing larger components

9.1.2 Testing larger components that go beyond our code base

9.2 Database and SQL testing

9.2.1 What to test in a SQL query

9.2.2 Writing automated tests for SQL queries

9.2.3 Setting up infrastructure for SQL tests

9.2.4 Best practices

9.3 System tests

9.3.1 An introduction to Selenium

9.3.2 Designing page objects

9.3.3 Patterns and best practices

9.4 Final notes on larger tests

9.4.1 How do all the testing techniques fit?