Skip to content

Commit 38f9415

Browse files
author
Jesper Sandström
committed
Implement given-when-then style tests for EffectRouterSpec
1 parent c39dc39 commit 38f9415

File tree

3 files changed

+178
-0
lines changed

3 files changed

+178
-0
lines changed

Mobius.xcodeproj/project.pbxproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
025BB529244DA65100E80BD2 /* ConnectableMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 025BB528244DA65100E80BD2 /* ConnectableMap.swift */; };
1111
025BB52C244DA6BF00E80BD2 /* ConnectableMapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 025BB52A244DA68500E80BD2 /* ConnectableMapTests.swift */; };
1212
025BB52D244DA6C400E80BD2 /* ConnectableMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 025BB528244DA65100E80BD2 /* ConnectableMap.swift */; };
13+
027D4519244DE4D100375BB5 /* EffectRouterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027D4518244DE4D100375BB5 /* EffectRouterSpec.swift */; };
14+
027D451C244DE7C600375BB5 /* EffectRouterSpecTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027D451A244DE7C000375BB5 /* EffectRouterSpecTests.swift */; };
15+
027D451D244DE7CD00375BB5 /* EffectRouterSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027D4518244DE4D100375BB5 /* EffectRouterSpec.swift */; };
1316
02BED1BB21DD20D20093FB47 /* ConnectableContramap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9CE80421197FE000DB79A7 /* ConnectableContramap.swift */; };
1417
02C4061D2373078400BD7ED8 /* EffectExecutor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C4061C2373078400BD7ED8 /* EffectExecutor.swift */; };
1518
02C40621237422EF00BD7ED8 /* EffectRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C40620237422EF00BD7ED8 /* EffectRouter.swift */; };
@@ -297,6 +300,8 @@
297300
/* Begin PBXFileReference section */
298301
025BB528244DA65100E80BD2 /* ConnectableMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectableMap.swift; sourceTree = "<group>"; };
299302
025BB52A244DA68500E80BD2 /* ConnectableMapTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectableMapTests.swift; sourceTree = "<group>"; };
303+
027D4518244DE4D100375BB5 /* EffectRouterSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EffectRouterSpec.swift; sourceTree = "<group>"; };
304+
027D451A244DE7C000375BB5 /* EffectRouterSpecTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EffectRouterSpecTests.swift; sourceTree = "<group>"; };
300305
02C4061C2373078400BD7ED8 /* EffectExecutor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EffectExecutor.swift; sourceTree = "<group>"; };
301306
02C40620237422EF00BD7ED8 /* EffectRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EffectRouter.swift; sourceTree = "<group>"; };
302307
02C40622237425E100BD7ED8 /* EffectRouterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EffectRouterTests.swift; sourceTree = "<group>"; };
@@ -821,6 +826,7 @@
821826
5B5F11B8213805C000911A57 /* MatcherUtils.swift */,
822827
5B19F71A21254CCD00074AD7 /* NextMatchers.swift */,
823828
5BB288A420999B750043B530 /* UpdateSpec.swift */,
829+
027D4518244DE4D100375BB5 /* EffectRouterSpec.swift */,
824830
);
825831
path = Source;
826832
sourceTree = "<group>";
@@ -842,6 +848,7 @@
842848
5B19F71D21255F9600074AD7 /* NextMatchersTests.swift */,
843849
5B57E8BD2125AD09001AFC71 /* TestUtil.swift */,
844850
5BB288AA20999B750043B530 /* UpdateSpecTests.swift */,
851+
027D451A244DE7C000375BB5 /* EffectRouterSpecTests.swift */,
845852
);
846853
path = Test;
847854
sourceTree = "<group>";
@@ -1269,6 +1276,7 @@
12691276
isa = PBXSourcesBuildPhase;
12701277
buildActionMask = 2147483647;
12711278
files = (
1279+
027D451D244DE7CD00375BB5 /* EffectRouterSpec.swift in Sources */,
12721280
2DF4C53A20DBE04B00A4B6DE /* UpdateSpec.swift in Sources */,
12731281
5B5F11BA213805C000911A57 /* FirstMatchers.swift in Sources */,
12741282
5B5F11BC213805C000911A57 /* MatcherUtils.swift in Sources */,
@@ -1403,6 +1411,7 @@
14031411
isa = PBXSourcesBuildPhase;
14041412
buildActionMask = 2147483647;
14051413
files = (
1414+
027D4519244DE4D100375BB5 /* EffectRouterSpec.swift in Sources */,
14061415
DDA64A6820A0AD5000150355 /* UpdateSpec.swift in Sources */,
14071416
5B5F11B9213805C000911A57 /* FirstMatchers.swift in Sources */,
14081417
5B5F11BB213805C000911A57 /* MatcherUtils.swift in Sources */,
@@ -1415,6 +1424,7 @@
14151424
isa = PBXSourcesBuildPhase;
14161425
buildActionMask = 2147483647;
14171426
files = (
1427+
027D451C244DE7C600375BB5 /* EffectRouterSpecTests.swift in Sources */,
14181428
DDA64A6920A0AD5200150355 /* UpdateSpecTests.swift in Sources */,
14191429
5B19F71E21255F9600074AD7 /* NextMatchersTests.swift in Sources */,
14201430
5B9CE814211C5BCD00DB79A7 /* InitSpecTests.swift in Sources */,
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright (c) 2020 Spotify AB.
2+
//
3+
// Licensed to the Apache Software Foundation (ASF) under one
4+
// or more contributor license agreements. See the NOTICE file
5+
// distributed with this work for additional information
6+
// regarding copyright ownership. The ASF licenses this file
7+
// to you under the Apache License, Version 2.0 (the
8+
// "License"); you may not use this file except in compliance
9+
// with the License. You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing,
14+
// software distributed under the License is distributed on an
15+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
// KIND, either express or implied. See the License for the
17+
// specific language governing permissions and limitations
18+
// under the License.
19+
20+
import MobiusCore
21+
import XCTest
22+
23+
public struct EffectRouterSpec<Effect, Event> {
24+
private let effectRouter: EffectRouter<Effect, Event>
25+
26+
public static func given(_ effectRouter: EffectRouter<Effect, Event>) -> Self {
27+
return EffectRouterSpec(effectRouter: effectRouter)
28+
}
29+
30+
public func when(_ effects: [Effect]) -> When {
31+
When(effectRouter: effectRouter, effects: effects)
32+
}
33+
34+
public func when(_ effects: Effect...) -> When {
35+
When(effectRouter: effectRouter, effects: effects)
36+
}
37+
38+
public struct When {
39+
fileprivate let effectRouter: EffectRouter<Effect, Event>
40+
fileprivate let effects: [Effect]
41+
42+
public func then(
43+
_ matchers: Predicate<[Event]>...,
44+
failFunction: @escaping AssertionFailure = XCTFail
45+
) {
46+
var gotEvents: [Event] = []
47+
48+
let connection = effectRouter.asConnectable
49+
.connect { event in
50+
gotEvents.append(event)
51+
}
52+
defer { connection.dispose() }
53+
54+
for effect in effects {
55+
connection.accept(effect)
56+
}
57+
58+
for matcher in matchers {
59+
if case .failure(let message, let file, let line) = matcher(gotEvents) {
60+
failFunction(message, file, line)
61+
}
62+
}
63+
}
64+
}
65+
}
66+
67+
public func expectEvents<Event: Equatable>(
68+
_ events: Event...,
69+
file: StaticString = #file,
70+
line: UInt = #line
71+
) -> Predicate<[Event]> {
72+
return { gotEvents in
73+
if events.allSatisfy({ gotEvents.contains($0) }) {
74+
return .success
75+
} else {
76+
return .failure(message: "Expected \(gotEvents) to contain: \(events)", file: file, line: line)
77+
}
78+
}
79+
}
80+
81+
public func expectSideEffects<Event: Equatable>(
82+
file: StaticString = #file,
83+
line: UInt = #line,
84+
_ sideEffects: @escaping () -> Void
85+
) -> Predicate<[Event]> {
86+
return { gotEvents in
87+
sideEffects()
88+
return .success
89+
}
90+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright (c) 2020 Spotify AB.
2+
//
3+
// Licensed to the Apache Software Foundation (ASF) under one
4+
// or more contributor license agreements. See the NOTICE file
5+
// distributed with this work for additional information
6+
// regarding copyright ownership. The ASF licenses this file
7+
// to you under the Apache License, Version 2.0 (the
8+
// "License"); you may not use this file except in compliance
9+
// with the License. You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing,
14+
// software distributed under the License is distributed on an
15+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
// KIND, either express or implied. See the License for the
17+
// specific language governing permissions and limitations
18+
// under the License.
19+
20+
import MobiusCore
21+
import MobiusTest
22+
import Quick
23+
import Nimble
24+
25+
final class EffectRouterSpecTests: QuickSpec {
26+
private enum Effect {
27+
case one
28+
}
29+
30+
override func spec() {
31+
context("Effect Router Spec") {
32+
it("supports matching events") {
33+
let effectRouter = EffectRouter<Effect, String>()
34+
.routeCase(Effect.one).toEvent { _ in
35+
return "test"
36+
}
37+
38+
EffectRouterSpec.given(effectRouter)
39+
.when(.one)
40+
.then(
41+
expectEvents("test")
42+
)
43+
}
44+
45+
it("supports checking for side effects") {
46+
var performedEffect = false
47+
let effectRouter = EffectRouter<Effect, String>()
48+
.routeCase(Effect.one).to { _ in
49+
performedEffect = true
50+
}
51+
52+
EffectRouterSpec.given(effectRouter)
53+
.when(.one)
54+
.then(
55+
expectSideEffects {
56+
expect(performedEffect).to(beTrue())
57+
}
58+
)
59+
}
60+
61+
it("supports multiple matchers") {
62+
let effectRouter = EffectRouter<Effect, String>()
63+
.routeCase(Effect.one).to { _, callback in
64+
callback.end(with: "test1", "test2")
65+
return AnonymousDisposable {}
66+
}
67+
68+
EffectRouterSpec.given(effectRouter)
69+
.when(.one)
70+
.then(
71+
expectEvents("test1"),
72+
expectEvents("test2"),
73+
expectEvents("test1", "test2")
74+
)
75+
}
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)