Over the course of the last several years, Google’s Flutter and Meta’s React Native have duked it out in an effort to win over not only market share but also the hearts and minds of the open source community of developers.
When it comes to writing contemporary multi-platform applications, no other tools do it better. Flutter offers a rich toolkit of pre-built widgets while React Native has a more user-friendly declarative UI. Flutter is popular with mobile app development while React Native finds more popularity in web app development circles.
Yet in the long list of comparable features, one aspect is often overlooked—testing.
Each Software Development Kit (SDK) provides its way of writing, grouping, and running tests. (And indeed you may well have your own preference!) In this post, we will discuss how Flutter and React Native handles testing, and along the way take a look at some of the differences between the two.
But before we do that, let’s take a step back and look a little closer at both Flutter and React Native.
What is Flutter?
Developed by Google and first released in 2017, Flutter is an open-source framework that allows developers to build multi-platform applications from a single code base. In short, this means you can develop one app, and then deploy it as a mobile iOS or Android App, a Windows, macOS, and Linux desktop app, and a web app—all from one repository of code.
Flutter uses Dart, a server-side object oriented programming language developed by Google. With the relative ease of use, incredible open source libraries, and development tooling, many of today’s most popular applications were built using Flutter, including Google Ads and Alibaba’s huge Xianyu app.
Flutter brings a lot of ease-of-use features to the table. For example, with Flutter, you can simplify your code base, improving time-to-market and allowing for easy changes across platforms.
What is React Native?
In 2018, React Native boasted the second highest number of contributors of any repository on GitHub and is used for the production of thousands of popular mobile apps today. This includes not only Meta platforms like Facebook, Instagram, and Oculus, but also apps by Walmart, Tesla, and even Microsoft Outlook.
So, what what about testing? If you’re deploying code across every device, you need to make sure it works on every device, right? Each SDK Recommends writing unit, widget (or component), and integration tests for your code base. Note that each type of test offers a unique and important view into the health of an application. A well-rounded testing strategy involves all three. Here’s an overview of each.
Unit tests validate a single function, method, or class and ensure that the smallest units of functionality are operating correctly. The goal of a unit test is to verify the accuracy of logic under multiple conditions. If there is a function that adds two numbers together, we’d want to verify it outputs 10 when 5 and 5 are provided. We would also want to write tests for edge cases. What happens when two large numbers are provided or if only one number is provided?
Widget tests and component tests
Widget tests or component tests validate that a single component is behaving correctly when interacted with and renders correctly. If one of our widgets is a calculator, a unit test will evaluate if a function correctly adds two numbers, and a widget test will verify if the calculator widget displays the output when the ‘=’ button is pressed, and if the component renders the entire component correctly.
Integration testing and end-to-end testing
Integration testing, also called end-to-end testing, tests the application—or multiple pieces of the application—together. Integration tests verify that the system components are working together correctly. In general, integration tests should only be run if all other types of testing have been passed first.
Writing tests for React and Flutter
The real comparison between writing Flutter and React tests relies on comparing their respective testing libraries as well as their frameworks, Jest and Dart. Developers may find themselves preferring one over the other for their own reasons. We’re not going to try to tell you which one is better—each has its pros and cons—so we’ll just lay out what to expect when it comes to testing in both.
React and Jest
Jest’s powerful mocking library makes it simple to stub out and mock unit test dependencies. A robust collection of mock functions allow you to quickly mock services and functions to utilize across your tests. Classes can also be automatically mocked, providing a mock constructor and a mock version of all methods. This makes writing tests much faster.
Another powerful React test feature is snapshots, which renders a UI component, takes a snapshot, and compares it to a previously rendered snapshot. This helps prevent unexpected changes.
Writing React tests
Jest unit tests are easily written using It, Expect, ToBe, which provides an excellent syntax for easily understanding what the test is, what’s expected, and the actual result:
- IT: is a string description of what the test will cover, the given input, and the expected result
- Expect: will take the function being tested, along with whatever arguments the function needs
- ToBe: is the assertion itself, that will indicate if the test passes or fails.
You can easily group texts together by using the describe class. For example, we can group calculator functions together under one testing group and run them together.
Integration/End-to-End (E2E) Tests
So far we’ve dealt with testing the code implementation of the mobile app. There has been no guarantee that they will function on a particular device. E2E testing involves using an emulator to simulate testing on a device. These emulators allow us to control elements on the screen, including swiping, button pressing, and text inputs and making assertions about the result.
Testers can use the Detox framework, which is tailored for React Native apps, to create and run E2E tests.
Flutter and Dart
For testing, Dart uses Package: test, which provides a standard way of writing tests with Dart. The framework can be used to write single tests, or to group tests together. The package allows you to write both synchronous and asynchronous tests in a similar manner.
@Tags, short strings you can use to categorize tests or test groups, allow you to create custom configurations and associate them to certain tests. For example, you can use a tag to indicate if a certain test should wait longer before timing out due to external dependencies. Use tags to also filter tests to execute, making it easier to specify which tests you want to run.
While Flutter doesn’t provide the flexible mocking capabilities of Jest, developers can take advantage of the dart mockito library, inspired by the open-source Mockito mock framework, to generate mocks from imports.
Writing Flutter tests
Writing unit tests in Flutter is similar to Jest with some initial setup requirements. First, add the test dependency and create the test file. In the test file, import your class and package:test.
Call the Test() function in Void Main (). The Test() method contains a string description of the test, much like ‘It’ in Jest. Then execute your method and use Expect to assert the result.
As with describe in Jest, you can group similar tests together with the group() function to easily execute them in the future for integration testing.
Here are a few quick take-aways to consider when comparing Flutter and React Native:
- Flutter offers a strong set of libraries and ‘hot reload’ which allows instant testing feedback when changes are made to code.
- Both Flutter and React Native offer great tools to quickly mock dependencies.
- React Native Jest can use Snapshots to easily capture and compare UI components.
Disclaimer: The views and opinions expressed above are those of the contributor and do not necessarily represent or reflect the official beliefs or positions of Sofy.