Skip to content

Commit

Permalink
Update README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
Felix Jendrusch committed Aug 19, 2015
1 parent 3e65704 commit 81f58ae
Showing 1 changed file with 82 additions and 9 deletions.
91 changes: 82 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
# Dobby

Dobby provides a few helpers for mocking and stubbing using expectations.
Dobby provides a few helpers for mocking and stubbing.

## Expectations
## Matchers

Expectations can be matched with values, serving as the fundamental building block for mocking and stubbing. There are many functions that help creating expectations for (equatable) types, including tuples, arrays, and dictionaries with equatable elements:
Matchers can be matched with values, serving as the fundamental building block for mocking and stubbing. There are many functions that help creating matchers for (equatable) types, including optionals, tuples, arrays, and dictionaries with equatable elements:

```swift
matches { $0 == value } // matches value
any() // matches anything
not(0) // matches anything but 0
none() // matches Optional<T>.None (nil)
some(1) // matches Optional<T>.Some(1)
equals(1) // matches 1
equals((1, 2)) // matches (1, 2)
equals((1, 2, 3)) // matches (1, 2, 3)
Expand All @@ -18,28 +21,98 @@ equals([1, 2, 3]) // matches [1, 2, 3]
equals([1: 1, 2: 2, 3: 3]) // matches [1: 1, 2: 2, 3: 3]
```

Expectations may also be nested:
Matchers may also be nested:

```swift
matches((matches { $0 == 0 }, any(), 2)) // matches (0, _, 2)
matches((not(equals(3)), some(any()))) // matches (not(3), _)
matches([any(), equals(4)]) // matches [_, 4]
matches(["key": matches { $0 == 5 }]) // matches ["key": 5]
```

## Mocks

Mocks can be used to verify that all set up expectations are matched with the recorded interactions. Verification is performed in order and all expectations must match an interaction and vice versa:
Mocks can be used to verify that all set up expectations have been fulfilled.

### Strict mocks

By default, mocks are strict and the order of expectations matters, meaning all interactions must be expected and occur in the order they were expected:

```swift
let mock = Mock<[Int]>()
mock.expect(matches([any(), matches { $0 > 0 }])) // expects [_, n > 0]
mock.record([0, 1])
mock.record([0, 1]) // succeeds
mock.verify() // succeeds
mock.record([1, 0]) // fails (fast)
```

The order of expectations may also be ignored:

```swift
let mock = Mock<[String: Int]>(ordered: false)
mock.expect(matches([0, 1]))
mock.expect(matches([1, 0]))
mock.record([1, 0]) // succeeds
mock.record([0, 1]) // succeeds
mock.verify() // succeeds
mock.record([0, 0]) // fails (fast)
```

### Nice mocks

Nice mocks allow unexpected interactions while still respecting the order of expectations:

```swift
let mock = Mock<[Int?]>(strict: false)
mock.expect(matches([some(0)]))
mock.expect(matches([some(any())]))
mock.record([nil]) // succeeds
mock.verify() // fails
mock.record([1]) // fails (fast)
mock.record([0]) // succeeds
mock.record([1]) // succeeds
mock.verify() // succeeds
```

Of course, nice mocks can ignore the order of expectations too:

```swift
let mock = Mock<[String: Int?]>(strict: false, ordered: false)
mock.expect(matches(["zero": some(0)]))
mock.expect(matches(["none": none()]))
mock.record(["none": nil]) // succeeds
mock.record(["zero": 0]) // succeeds
mock.verify() // succeeds
```

#### Negative expectations

In addition to normal expectations, nice mocks allow negative expectations to be set up:

```swift
let mock = Mock<Int>(strict: false)
mock.reject(0)
mock.record(0) // fails (fast)
```

### Verification with delay

Verification may also be performed with a delay, allowing expectations to be fulfilled asynchronously:

```swift
let mock = Mock<Int>()
mock.expect(1)

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(1.0 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
mock.record(1) // succeeds
}

mock.verifyWithDelay(2.0) // succeeds
```

## Stubs

Stubs, when invoked, return a value based on their set up behavior, or, if an interaction is unexpected, return `nil`. Behavior is matched in order, i.e., the function or return value associated with the first expectation that matches an interaction is invoked/returned:
Stubs, when invoked, return a value based on their set up behavior, or, if an interaction is unexpected, return `nil`. Behavior is matched in order, i.e., the function or return value associated with the first matcher that matches an interaction is invoked/returned:

```swift
let stub = Stub<(Int, Int), Int>()
Expand Down Expand Up @@ -75,14 +148,14 @@ class MyClassMock: MyClass {
let myMethodMock = Mock<(String, String)>()
let myMethodStub = Stub<(String, String), String>()
override func myMethod(fst: String, _ snd: String) -> String {
myMethodMock.record(fst, snd)
myMethodMock.record((fst, snd))
// Call super if the stub doesn't define any behavior for the interaction.
return myMethodStub.invoke(fst, snd) ?? super.myMethod(fst, snd)
}
}
```

The test subclass allows you to verify that all your set up expectations are matched with the recorded interactions and enables you to change its behavior on-the-fly:
The test subclass allows you to verify that all your set up expectations are fulfilled and enables you to change its behavior on-the-fly:

```swift
let myClassMock = MyClassMock()
Expand Down

0 comments on commit 81f58ae

Please sign in to comment.