Testing As your codebase expands, small errors and edge cases you don’t expect can cascade into larger failures. One way to prevent fragile programming is to test your code before releasing it into the wild. Here are different automated ways to ensure your app works as expected, ranging from static analysis to end-to-end tests.
Why Test
Humans make mistakes, and testing helps uncover them
- It ensures that your code continues to work in the future as you add features or upgrade dependencies
- Tests serve as documentation for new people joining your team
- More automated testing means less time spent with manual QA
Writing Tests
The default template of React Native ships with Jest testing framework
Unit tests
These cover the smallest parts of code, like individual functions or classes.
Testing User Interactions
Aside from rendering some UI, your components handle events like onChangeText for TextInput or onPress for Button.
- Test the component from the user perspective-what’s on the page? What changes when interacted with?
- Make assertions using rendered text or accessibility helpers
- Avoid testing implementation details like props or state
Static Analysis
Check your code for errors as you write it, without running any of it
- Linters analyze code to catch common errors
- Type checking ensures that the construct you’re passing to a function matches what the function was designed to accept
- React Native comes with two such tools configured out of the box: ESLint and Flow
Testing Rendered Output
With snapshot testing, you typically first implement your component and then run the snapshot test.
- The snapshot test then creates a snapshot and saves it to a file in your repo as a reference snapshot.
- Any future changes to the component render output will change its snapshot, which will cause the test to fail.
Writing Testable Code
To start with tests, you first need to write code that is testable.
- Separate the view part of your app-your React components-from your business logic and app state (regardless of whether you use Redux, MobX or other solutions).
- Business logic testing should be independent of the components themselves, whose job is primarily rendering your app’s UI.
Component Tests
React components are responsible for rendering your app, and users will directly interact with their output
- Two things to test: interaction and rendering
- Interaction: to ensure the component behaves correctly when interacted with by a user (eg. when user presses a button on the UI)
- Rendering
- For example, if you have a button that has an onPress listener, test that the button appears correctly and that tapping the button is correctly handled by the component
End-to-End Tests
Verifies that your app is working as expected on a device from the user perspective
- E2E tests give you the highest possible confidence that part of your application is working
- The tradeoffs include: they are more time consuming compared to the other types of tests
- They are slower to run
- Flaky tests are more prone to flakiness
Summary
There are many ways to test your app
Structuring Tests
Short and ideally test only one thing
- Cover the following: Given – some precondition
- When – some action executed by the function that you’re testing
- Then – the expected outcome
- Ensure that your tests are completely independent of one another
- Each test in your suite must be executable on its own without first running some other test
Mocking
Replace some dependency of your code with your own implementation
- Using real objects in your tests is better than using mocks but there are situations where this is not possible
- Jest comes with support for mocking from function level all the way to module level mocking
Integration Tests
When writing larger software systems, individual pieces of it need to interact with each other
- In integration testing, real individual units are combined and tested together to ensure that their cooperation works as expected
- The line between what is a unit test and an integration test may not always be consistent
- For this guide, your test falls into “integration testing” if it: Combines several modules of your app
- Uses an external system
- Makes a network call to other application
- Does any kind of file or database I/O