How to Create Mocks and Stubs in Swift

Without 100% support for a mocking framework like OCMock, I found myself needing to get creative when building mock objects and method stubs in Swift unit tests.  The great thing about testing is that you’re…well… testing things out to see if they’ll work, and I found a solution that I’m pretty happy with for now.  I’m open to better ways, so leave a comment if you’ve had good results using a different design!

The process is essentially this (example to follow):

  1. Ensure that the class that you would like to test is designed so that you can substitute your mock for the real one that’s used in your class’ implementation
  2. Create an XCTestCase  class with a test function in your unit test project
  3. Within the function body create a nested class
  4. Make the nested class inherit from the real object you’re trying to mock / create a method stub for
  5. You can give the nested class a name such as Mock[ObjectName]
  6. Configure the mock object however you need by setting its properties or overriding its function implementations with stubbed implementations – no need to override every function… only the one(s) that your class calls during the test at hand
  7. Instantiate the class you’re testing and pass in an instance of the mock object you just nested in the test function to your class somehow (either through its initializer, by setting a property on the class, or by passing it into the method under test via parameter — however you intended to ‘inject’ the mock from step 1 is what you should do)
  8. XCTAssert…

Let’s see those 8 steps in action for those of us who are more visually inclined.

EDIT:  July 22, 2014 – I’ve added a simple XCode Project to GitHub for those interested in seeing the setup directly in XCode at  https://github.com/andrewcbancroft/MocksAndStubs

The scenario that I’d like to use a mock class in is this:  I have a CoreData application and I’d like to be able to mock the NSManagedObjectContext  so that instead of making actual database fetch requests, I can just provide stubs of various sorts with the kinds of responses I’d expect from the real database calls to ensure my class will do the right thing based on predictable results.  To do this I begin at step 1…

1.  Ensure that the class that you would like to test is designed so that you can substitute your mock for the real one that’s used in your class’ implementation

In the example class below, I intend to provide the NSManagedObjectContext  dependency through the class’ initializer which will set a property that is used by my class’ methods later on, but you could easily use some other way of performing “dependency injection”.  The initializer strategy just makes it super clear in my mind what the class’ dependencies are, so that’s what I’m going to do here.  Have a look:

Now, let’s say that my example class has a member function called  databaseHasRecordsForSomeEntity  that returns a Bool  value of true if the resulting array of a fetch request contains objects, and a Bool  value of false if the result array of a fetch request is empty.  The completed class looks like this:

I want to test if  databaseHasRecordsForSomeEntity  does what I intend it to do. So…

2.  Create an  XCTestCase  class with a test function in your unit test project

Just listing this for completeness

Next comes the way to make the mock.  Read steps 3-5 and then look below for a code example of what the skeleton will look like.

3.  Within the function body create a nested class

4.  Make the nested class inherit from the real object you’re trying to mock / create a method stub for

5.  You can give the nested class a name such as Mock[ObjectName]

 6.  Configure the mock object however you need by setting its properties or overriding its function implementations with stubbed implementations – no need to override every function… only the one(s) that your class calls during the test at hand

For my example, I’m going to stub out the executeFetchRequest  method so that it returns an array with one object in it.  This is really the part where you have to determine what you’re testing and what you expect the stubbed results to be.  Whatever you decide, the way to stub a method is simply to override it in the mock you’re implementing.  Here’s how I implemented the  executeFetchRequest  stub for my example:

We’re ready to perform the test and assert the results.  Read steps 7-8 and take a look at the code example below step 8:

7.  Instantiate the class you’re testing and pass in an instance of the mock object you just nested in the test function to your class somehow (either through its initializer, by setting a property on the class, or by passing it into the method under test via parameter — however you intended to ‘inject’ the mock from step 1 is what you should do)

8.  XCTAssert…

From step 1, I intended to pass an NSManagedObjectContext instance to the initializer of MyClass, so that’s what I’ll do in my test.  I’ll then perform the XCTAssert on the return value of my method under test:

 

Running the tests at this point should produce a passing test using the mock object in place of a real NSManagedObjectContext that calls a database!

Now, if I wanted to test the “false” branch of my class’ method, I could simply create another test method following the same steps, only this time, I’d provide a new implementation for the overridden executeFetchRequest  method that’s appropriate:

And that’s a wrap – happy mocking and stubbing in Swift!

EDIT:  July 22, 2014 – I’ve added a simple XCode Project to GitHub for those interested in seeing the setup directly in XCode at  https://github.com/andrewcbancroft/MocksAndStubs

  • Scott Ross

    Do you have your unit test as a member of the regular project? I can’t figure out how to subclass when the base class is in the other project (as opposed to being in the test project)

    • Andrew Bancroft

      Hey Scott!

      My unit test is a member of the [ProjectName]Tests project. However, I know what you’re saying – I’ve had issues with XCode not “seeing” my classes from the main project.

      What I’ve had to do is click the file name for the class I want to test (in my main project), and check the “Target Membership” area of the inspector panel to make sure that the checkbox is selected for my Tests project. I’m not sure if this is normal or if there’s another way to do it, but that seems to alleviate the issues I’ve had. Does this work for you?

      • Scott Ross

        The import works!
        And you also educated me that a class get be apart of two target memberships. I had a brain lock and thought it had to be one or the other.
        Anyway, I been messing around with your example and so far its the best way given that there isn’t a library out there for swift /mocks yet

        • Andrew Bancroft

          Fantastic! I’m super glad the post is helpful. If you think of ways to improve upon this, I’d love to hear about it!

    • Andrew Bancroft

      I just discovered something: If you add an import statement for your main project name to the top of your test.swift file, that may allow you to avoid checking the “Target Membership” box. So in my case, if my project name is “MyProject”, if I add “import MyProject” to the top of my test file, XCode recognizes my class…

  • Adrian

    Hi Andrew, thanks for this great info!

    I’m having an issue though with my tests, I’ve mocked executeFetchRequest as below:

    override func executeFetchRequest(request: NSFetchRequest, error: NSErrorPointer) -> [AnyObject]?
    {
    let transaction: AnyObject = Transaction()
    return [transaction]
    }

    When this code is executed I get the following error:

    CoreData: error: Failed to call designated initializer on NSManagedObject class ‘MyTests.Transaction’

    Any ideas why this is failing? Transaction is a CoreData model.
    Thanks for any help

    • Andrew Bancroft

      I’m thinking about this one, Adrian – It may take me a bit to respond fully because I’m heading out of town for a few days. If I discover the answer though, I’ll reply again or write up another blog post.

      Do let me know if you figure out how to resolve the issue!

      • Adrian

        Hi Andrew, I think I figured this out. I am now passing the instance of my mock context to the init method of my core data object like so:

        override func executeFetchRequest(request: NSFetchRequest, error: NSErrorPointer) -> [AnyObject]?
        {
        var entity = NSEntityDescription()
        entity.name = “Transaction”
        entity.managedObjectClassName = “Transaction”
        let transaction: AnyObject = Transaction(entity: entity, insertIntoManagedObjectContext: self)
        return [transaction]
        }

        Seems to have solved the issue in my instance.
        Hope this helps
        Adrian

    • Andrew Bancroft

      So first of all, I apologize, Adrian – this post and the code associated with it and the GitHub example were totally broken. It hadn’t been updated since early betas of XCode 6, so it’s likely that things were broken for a while. : I’ve now corrected the compilation issues and fixed the code examples in the post.

      Second: I think I’ve also run into the problem you’re having and I’m not entirely sure how to overcome it. The designated initializer for a NSManagedObject class/subclass is technically init(entity:insertIntoManagedObjectContext:). Apple docs specifically say that we should not initialize one of these by simply calling init(), or in your case, Transaction(). Here’s the relevant documentation page: https://developer.apple.com/library/mac/Documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObject_Class/index.html#//apple_ref/occ/instm/NSManagedObject/initWithEntity:insertIntoManagedObjectContext:

      NSManagedObjects are “dynamically” generated and initialized, so I’m honestly unsure of how to test methods which would return an instance of one of those without it getting complicated quickly. I’m researching this though, and if I discover anything helpful, I’ll definitely write about it.

  • Pingback: Don't Write Legacy Swift - Andrew Bancroft()

  • Raphael Oliveira

    Hey, I have a question, in the same scenario, if I want to test that at a given time an UIAlertView is shown, how would you do it? Would you really transform it into a dependency? So if my view controller uses UIAlertView, UIAlertController, NSUserDefaults etc, would you put them as a dependency? Is it really great? What are the odds of we actually wanting to change to another type to justify dependency injection?

    • Andrew Bancroft

      Well, I’ve got a challenging question on my hands here, Raphael. :] Thanks for asking it!

      If you truly want to test that, say, that a UIAlertView was shown (ie that the show() method was called on it), the odds of you wanting to change to another type in your view controller are pretty much guaranteed. This is because you’ll need to go down the path of creating a “test double” / fake object with some overridden behavior and getting into your View Controller / method somehow, which would require dependency injection.

      The full explanation for how to do this is a little difficult to put into the comments here, so be on the lookout for a new post with a better explanation if you’re interested. But the idea is, if I can get a “fake” UIAlertView into my controller (I personally just tried it out by assigning my fake UIAlertView to a property on my controller), I can subclass UIAlertView, override the show() method to perform some behavior that I can test (rather than actually showing an alert, since that’s not desirable in a unit test).

      My fake UIAlertView has a boolean property on it called “showWasCalled”. The overridden show() method sets this to true. I can then assert that showWasCalled == true in my test, so long as I can get that instance into my controller and call the method that will do the showing.

      Again, a better-explained post will come at some point, along with an example. I’ve just got to find the time to build it out. Please let me know if this was semi-helpful / answers your question about dependency injection. As to whether or not it’s desirable – I guess it just depends on how badly you want to test that behavior.

      Thanks again for your comment, Raphael!

      • Raphael Oliveira

        Hi Andrew thanks for the answer. I ended up using a similar solution to yours. I create an extension of UIAlertView redeclaring the show function throwing a notification and in my test I expect this notification with the neat expectationForNotification that XCTest provide to us. In that case I don’t have to pass the UIAlertView using DI and a property to hold the alert view (this really bothers me because I don’t think I’d change to another component) but I can still test the behaviour. The caveat is that the Extension docs explicitly say “Extensions can add new functionality to a type, but they cannot override existing functionality.” so I thought redeclaring -show wouldn’t work but it does. I’m not sure if it will stop working on the future though.

  • Pingback: Swift Unit Testing Resources - Andrew Bancroft()

  • Andrew Bancroft

    Hi ZiLang!

    I may need to write up a blog post on this for further explanation. In general, think of the mock object as the thing that you control and customize and then send into the system you’re trying to test.

    Sometimes a mock object will affect the class or function you’re testing, but since you set up the mock how you need, the effects it has on the system are predictable. In other words, they’re a way to control the system you’re testing.

    Oftentimes, mocks are also used as a way to isolate things in the system you’re testing so that you can focus in on the one area of the system you’re trying to observe. In this way, think of mocks as the things that keep everything else in the system “normal” or “inert” while you poke and prod at one specific function with a test.

    I’ll try and think on this more and formalize it a bit into an actual blog post (not sure on timeline though). Let me know if any of that made sense and where things are still fuzzy, though.

    • ZiLang

      Thanks, your reply make sense.

      But I have another question. You embed the Mock object in every test function. There could be tons of duplicated code if there are too many test functions. Why don’t you add the nested class in Test case class?

      • Andrew Bancroft

        I absolutely agree – Whenever the “mock” could be used between multiple tests, I’d recommend moving it out of the function itself and into the test case class. In your test refactor step, you’d detect that you’re about to repeat the same fake object logic and simply move it at that time.

        I stuck it in the function itself because a lot of times, you need customized “fake object” behavior per test. The fake object definition’s location can give you clues as to its customized nature to the method under test.

        Thanks for sharing your thoughts on this!

  • Pingback: Xcode 6: Usable Testing « Under The Bridge()

  • Maxime Capelle

    Hi Andrew,

    As you said, one important point here is that your app is designed to be testable. In our case, it means that we can easily access the classes dependencies to replace them by mocks or stubs.

    Before trying to use TDD (to test my controllers), I used massively singletons. But the problem with singletons is that they hide the dependencies and I can’t replace them “on the go” by stub for testing purpose.

    In your exemple you are passing the context as an argument in the init method of your class. Are you doing the same thing for controllers? I mean, do you create all your dependencies (NSManagedObjectContext, Network services, …) in your appDelegate and then you pass them from controllers to controllers with public properties?

    If you have any tips to make an app testable, I’ll be pleased to hear about them 🙂

    Thanks for your blog post

    • Andrew Bancroft

      Hey Maxime!

      You’re absolutely right – it comes down to it, we need to be able to say something like “all things being equal, when this [function] is called, [x] should be the result”. The thing that allows us to keep “all things equal” are the fake instances we can design and inject into the class or function we’re testing.

      For my own apps, I do, in fact, pass the NSManagedObjectContext instance along through property “setter injection”. I’m still not 100% sure I love that practice, but when it comes down to it, it sure enables a lot of testing when I can swap out the sqlite data store with an in-memory store.

      I’ve been pondering testability as a subject lately. I wrote a “testability tip” post on making things public where appropriate to enable testing (http://www.andrewcbancroft.com/2015/04/15/testability-tip-for-swift-developers-public-over-private/). I have more “testability tips” on the way – they’re just in my “blog ideas” queue. I try and rotate topics to keep things interesting, but be on the lookout here in the next few weeks for a second “testability tip”!

      Thanks for your comment and feedback, Maxime!

      • Hi Andrew,

        Thank you for this great post. It basically shows how to properly write a test by isolating the subject under test and stub other objects by simply returning some predetermined values. I think you nailed the very essence of testing.

        As for the constructor dependency injection and having to pass dependency objects, I found one way to avoid that is to use protocols. For example, to avoid having to write a custom init for CustomViewController just to inject an NSManagedObjectContext instance, I could just make a CustomViewControllerProtocol and put let context: NSManagedObjectContext! inside it. Make CustomViewController conform to it. Then when I need to use a mockContext, I can just do vc.context = MockContext(). I especially like the explicitness of using protocols.

        BTW, your testability link has an extra ‘)’ at the end.

        • Andrew Bancroft

          Great thoughts on the use of Protocols there!

  • Instead of having the mock inside the test method, what about having the mock inside the XCTestCase class but outside of any test method? That way, the mock can be reused for different cases (empty and non-empty). To avoid writing a full implementation inside the mock, the test methods can also inject an empty or non-empty array to the mock using dependency injection too. That way, it can cut down some redundancy.

    Have you experimented with moving the mock classes outside of the test files and into some folders inside the test case in the project navigator? This is more about organizing than testing, but I am really interested in learning what your preferences are.

    • Andrew Bancroft

      Most definitely some good points there. I think what I’d probably end up doing is this: When I wrote a second (or third or forth) test that seemed to re-use the same mock/fake object, I’d probably move it out of the test method itself up into the test case. And if it was useful outside the test case later on, I’d move it out to where it was more visible. Does that make sense?

      So the approach I tend to take is to refactor it as I need to. If it’s super obvious that I’ll reuse the fake object, I may go ahead and start off with it being not-so-deeply-nested, but in general, I just stick it where I need it for that particular test until I see the re-use case.

      • Definitely agree with refactoring as it becomes necessary. Currently, it works well when I leave the mock/stub/spy inside the XCTestCase subclass. It’s just when there are a lot of these test doubles that it kinda obscures the test case itself. So I am contemplating moving them out to its/their own file(s). But the context is lost a bit when I do that.

  • @andrewcbancroft:disqus Have you had to do a mock like this for a NSManagedObject? I’m trying to subclass an existing NSManagedObject class but I’m getting some strange side effects that I can’t figure out.

    One of the complications I’m running into is that I have create “mocks” of two classes. One class has to return the NSManagedObject one. I’m getting “undeclared type” when I try to cast it as my mock object.

    • Walt

      Did anyone figure this out. I attempted to mock a NSManagedObject subclass and override vars as neccessary. The issue here is that I get this error :Failed to call designated initializer on NSManagedObject class. I love this approach otherwise.