Unit Testing in iOS using ReactorKit, Quick & Nimble, RxBlocking, Swift 4.1

Sourav Chandra
Pulse
Published in
3 min readMay 20, 2018

Getting Started

We will be using RxBlocking to verify the state of your Reactor (ViewModel). We will also use Stubber to mock our network requests. Finally, your Podfile should contain the following:

def development_pods
pod 'ReactorKit'
pod 'RxSwift'
pod 'RxCocoa'
end
def testing_pods
pod 'RxBlocking'
pod 'Stubber'
pod 'Quick'
pod 'Nimble'
end

Simple Test Flow

A simple flow can involve sending an Action to your Reactor and testing the following things:

  1. State updates: Checking the updates to each state variable when an action is performed to verify your Reactor logic.
  2. Execution counts: Making sure that network requests and other function calls are being made the correct number of times.
  3. Making sure that the state is emitting the correct number of times.

Initial Setup

I use the following folder structure for my tests:

Folder Structure for Unit Test Cases

Stubbed Repositories: Repositories are structs that expose public methods which you can use to fetch data using a network request. Stubbed Repositories folder contains mock repos created using Stubber.

ReactorTests: Contains ViewModel/Reactor tests.

Stubs

Mocking your network request is very easy with Stubber.

A simple stub created using Stubber.

You can also verify the execution count of your stubbed method by using

Stubber.executions(signIn).count

Unit Tests

In order to test the logic inside Reactor, we need to consider the Reactor as a black box. I will feed an action as input and get UI states as output.

Reactor/ ViewModel as a black box

Below I’m triggering the signIn action with some invalid parameters which should ideally emit an error state after doing some validation inside Reactor in a synchronous fashion. I’ll use RxBlocking to block the flow of the code until my state observable emits one event.

Note the use of .delay() operator. Without it, there are chances of missing some events before the blocking statement on line 7 gets executed.

state emits one event as soon you subscribe to the stream which is usually the previous state which should be skipped. The skip(1) helps with this.

Using take(1) completes the stream after one emission. Otherwise RxBlocking will never allow the statement to fall through.

If the state doesn’t emit within 5 seconds, RxTimeoutException is thrown by RxBlocking and the test case fails automatically.

After extracting the state, Nimble is used to verify that the values of the state variables meet expectations.

The stream gets disposed right after all expectations are verified.

What if there are multiple state emissions?

Well if there are multiple emissions then instead of using first() operator in RxBlocking, we can use toArray() operator. toArray() will give you the array of states emitted in the subsequent order.

Then you can use expect to verify the state variables one by one.

Questions?

The complete project is available on Github. Feel free to share feedback or ask questions in the comments. :)

--

--

Sourav Chandra
Pulse
Writer for

Entrepreneur, Philanthropist and Swift Enthusiast with natural interest in UI/UX.