Documentation/Abstracts/Test Support.md
Every part of an application using Fluxor is highly testable. The separation of the `Action` (instructions), `Selector` (reading), `Reducer` (mutating) and `Effect` (asynchronous) make each part decoupled, testable and easier to grasp.
But to help out when testing components using Fluxor or asynchronous `Effect`s, Fluxor comes with a separate package (**FluxorTestSupport**) with a `MockStore`, `TestInterceptor` and an `EffectRunner` to make `Effect`s run syncronously.
FluxorTestSupport should only be linked in unit testing targets.
## Mocking out the `Store`
The `MockStore` can be used to mock the `Store` being used.
### Setting a specific `State`
With `MockStore` it is possible, from a test, to set a specific `State` to help test a specific scenario.
```swift
import FluxorTestSupport
import XCTest
class GreetingView: XCTestCase {
func testGreeting() {
let mockStore = MockStore(initialState: AppState())
let view = GreetingView(store: mockStore)
XCTAssert(...)
mockStore.setState(AppState(greeting: "Hi Bob!"))
XCTAssert(...)
}
}
```
### Overriding `Selectors`
The `MockStore` can be used to override `Selector`s so that they always return a specific value.
```swift
import FluxorTestSupport
import XCTest
class GreetingViewTests: XCTestCase {
func testGreeting() {
let greeting = "Hi Bob!"
let mockStore = MockStore(initialState: AppState(greeting: "Hi Steve!"))
mockStore.overrideSelector(Selectors.getGreeting, value: greeting)
let view = GreetingView(store: mockStore)
XCTAssertEqual(view.greeting, greeting)
}
}
```
## Intercepting state changes
**NOTE:** This is built into the `MockStore`.
The `TestInterceptor` can be registered on the `Store`. When registered it gets all `Action`s dispatched and state changes. Everything it intercepts gets saved in an array in the order received. This can be used to assert which `Action`s are dispatched in a test.
```swift
import FluxorTestSupport
import XCTest
class GreetingViewTests: XCTestCase {
func testGreeting() {
let testInterceptor = TestInterceptor<AppState>()
let store = Store(initialState: AppState())
store.register(interceptor: self.testInterceptor)
let view = GreetingView(store: store)
XCTAssertEqual(testInteceptor.stateChanges.count, 0)
view.updateGreeting()
XCTAssertEqual(testInteceptor.stateChanges.count, 1)
}
}
```
The `MockStore` uses this internally behind the `stateChanges` property.
## Running an `Effect`
An `Effect` is inherently asynchronous, so in order to test it in a synchronous test, without a lot of boilerplate code, FluxorTestSupport comes with an `EffectRunner` that executes the `Effect` with a specific `Action` and `Environment`. It is possible to run both `.dispatchingOne`,` .dispatchingMultiple` and `.nonDispatching`, but the result will be different.
When running `.dispatchingOne` and` .dispatchingMultiple`, it is possible to specify the expected number of dispatched `Action`s and the dispatched `Action`s will also be returned.
When running `.nonDispatching`, nothing is awaited and nothing is returned.
```swift
import FluxorTestSupport
import XCTest
class SettingsEffectsTests: XCTestCase {
func testSetBackground() {
let effects = SettingsEffects()
let action = Actions.setBackgroundColor(payload: .red)
let result = try EffectRunner.run(effects.setBackgroundColor, with: action)!
XCTAssertEqual(result.count, 1)
XCTAssertEqual(result[0], Actions.hideColorPicker())
}
}
```