Mocking at Swift

How do you mock an object in Swift?

The Mirror protocol sounded promising, but it does little now.

So far, the only approach I have found is to subclass and override all the methods of the mocking class. This, of course, is not a real layout, far from ideal and a lot of work.

Any other ideas?

Why not OCMock?

From source :

Can I use OCMock using the language bridge functionality?

Yes, but with limitations. If you are brave. At the moment, it is very experimental. There is no guarantee that OCMock will ever fully support Swift.

Known limitations:

  • Tests must be written in Objective-C
  • Objects to be mocked should inherit from NSObject
  • Lack of stubbing / expecting / verify class methods
+49
unit-testing swift mocking
Jun 11 '14 at 23:17
source share
7 answers

NSHipster touches on language features in Swift that make an unnecessary external mock library:

In Swift, classes can be declared in function definitions, allowing mock objects to be extremely autonomous. Just declare false methods of the inner class, overrides and [sic]:

 func testFetchRequestWithMockedManagedObjectContext() { class MockNSManagedObjectContext: NSManagedObjectContext { override func executeFetchRequest(request: NSFetchRequest!, error: AutoreleasingUnsafePointer<NSError?>) -> [AnyObject]! { return [["name": "Johnny Appleseed", "email": "johnny@apple.com"]] } } ... } 

Being able to subclass your external dependency in the local area plus the addition of XCTestExpectation solves many of the same problems as OCMock .

The only thing a library like OCMock provides very useful is its validation methods to ensure that layouts have been called. This can be added manually, but automatic addition is nice.

+27
Jul 23 '14 at 17:05
source share

I create my layouts by wrapping everything in a protocol. I use the layout class to match the protocol in question, for example:

 protocol Dog: class { var name: String { get } func bark() } class DogImpl: Dog { var name: String init(name: String) { self.name = name } func bark() { print("Bark!") } } class DogMock: Dog { var name = "Mock Dog" var didBark = false func bark() { didBark = true } } 

I use this in conjunction with dependency injection to achieve full testing coverage. These are many templates, but so far I have not had any problems with this approach.

As for the subclass taunting, you will run into problems with final classes or if they have non-trivial initializers.

+4
Mar 27 '17 at 14:33
source share

I want to point out something in addition to the notable answer - I don't know if this is a mistake or not.

If you somehow subclass NSObject (in my case, I have been subclassing UIView, which is an internal subclass of NSObject), you need to declare an overridden function with @objc , otherwise your test will not compile. In my case, the compiler itself crashes:

Segmentation Error: 11

So the following class:

 public class ClassA: UIView { @objc public func johnAppleseed() { } } 

Test the device as follows:

 class ClassATests: XCTestCase { func testExample() { class ClassAChildren: ClassA { @objc private override func johnAppleseed() { } } } } 
+2
May 29 '15 at 13:00
source share

You can achieve this kind of MockFive ridicule.

Its essence is that you need to create a layout “manually” of the source class that you want to make fun of -

but then you can muffle them dynamically, so you can use it where you need it and adjust its behavior there.

I wrote an article on how to use it here .

+1
Jan 11 '16 at 4:49 on
source share

I recommend using Cuckoo , which can handle most common bullying tasks.

Class examples:

 class ExampleObject { var number: Int = 0 func evaluate(number: Int) -> Bool { return self.number == number } } class ExampleChecker { func check(object: ExampleObject) -> Bool { return object.evaluate(5) } } 

Test example:

 @testable import App import Cuckoo import XCTest class ExampleCheckerTests: XCTestCase { func testCheck() { // 1. Arrange let object = MockExampleObject().spy(on: ExampleObject()) stub(object) { object in when(object.evaluate(any())).thenDoNothing() } let checker = ExampleChecker() // 2. Action checker.check(object) // 3. Assert _ = verify(object).number.get verify(object).evaluate(any()) verifyNoMoreInteractions(object) } } 
0
Jan 22 '18 at 22:07
source share

Due to the limitations you wrote, OCMock does not work very well in Swift (since each framework is highly dependent on runtime).

There are several fake frameworks for Swift, from semi-manual to almost fully automatic layout creation. Some of them are already listed in the answers, so I’ll just recommend the other one, which I am one of the authors.

https://github.com/MakeAWishFoundation/SwiftyMocky

I will not go into details, it has its own minor limitations, but from what I see, it has the widest set of functions from Swift frameworks (at least from those that I know), including support for generalized elements, members @objc and updating layouts when you write / change protocols (observer mode).

0
Dec 12 '18 at 19:16
source share

Maybe someone will find this useful - I use simple helpers inside my projects for prototyping and dependency checking based on the protocol (it helps a lot in architectures like VIPER): https://github.com/dratkevich/FakeEquatable

0
May 12 '19 at 8:52
source share



All Articles