Example of Moving Towards Integration Testing

John Tucker
codeburst
Published in
3 min readJul 8, 2018

--

Through a simple yet illustrative example, we explore the idea of replacing blindly seeking test coverage with unit tests with strategic integration tests.

The motivation of this article is born out of frustration at recently writing a lot of boilerplate unit tests in a front end project that didn’t feel very useful. At the same time, I happened to read the following excellent article that pointed me in a different direction; integration testing.

This example is a React + Redux web application using create-react-app for the build. The tests are written with Jest + Enzyme. The completed example is available for download.

The Application

Made the example as simple as possible and still illustrate the difference between testing approaches. The example has a button that toggles a boolean (true / false) state that controls the display of an On / Off display.

The Code

For completeness, we will walk through the code (six modules) that we are testing.

src/index.js: Entry point that renders the App component into the root DOM element

src/components/App/App.jsx: Creates the Redux store and injects it into the Room component

note: Normally, I would not have thought to create the store in the component’s render method; but it was needed for testing (explained later). Turns out to be not a problem because the App component is only rendered once in the application’s lifecycle.

src/components/App/Room/Room.js: Wraps the RoomView component with the connect higher-order-component (HOC); injects on (boolean) and toggleOn (function)

src/components/App/Room/RoomView/RoomView.jsx: Displays the On / Off value and provides the button that toggles the state

src/store/reducers.js: Uses combineReducers to combine all the reducers into a single one used to create store; trivial because only built with one reducer (on)

src/ducks/on.js: Used to manage the boolean state

Unit Testing

Writing unit tests amounts to testing each of the modules in isolation.

note: Skipped unit testing the one-line entry point (src/index.js); super declarative code (and didn’t spend time figuring out how to mock the dependencies).

src/components/App.test.jsx: Smoke test

src/components/App/Room/Room.test.jsx: Smoke test with mock store

src/components/App/Room/RoomView/RoomView.test.jsx: Tests that component renders properly and distinctly in both On / Off states

src/store/reducers.test.js: Smoke test

src/ducks/on.test.js: Tests functionality of action creators, reducers, and selectors (one of each)

Looking through these five files, much of the testing is of declarative code (simply covered by boilerplate smoke tests).

The only seemingly interesting parts are validating:

  • The proper and distinct rendering in RoomView.test.js
  • The initial state (false) in on.test.js
  • The handling the toggle action in on.test.js

Integration Testing

Thinking about what was interesting to test, we can rather create a single integration test that accomplishes this result.

src/integration.test.js

Observations:

  • We unmount the App component after each test to ensure that the tests are isolated from each other.
  • As indicated earlier, we also need to create the Redux store when rendering the App component to ensure that we have test isolation.

Conclusion

While it takes a bit more thought, it appears that creating strategic integration tests is a better (fewer files with better protection) testing approach than blindly writing unit tests.

✉️ Subscribe to CodeBurst’s once-weekly Email Blast, 🐦 Follow CodeBurst on Twitter, view 🗺️ The 2018 Web Developer Roadmap, and 🕸️ Learn Full Stack Web Development.

--

--