What is Mocking?

前端 未结 8 1121
遥遥无期
遥遥无期 2020-11-22 03:15

What is Mocking?                                                                                                    .

相关标签:
8条回答
  • 2020-11-22 03:56

    Other answers explain what mocking is. Let me walk you through it with different examples. And believe me, it's actually far more simpler than you think.

    tl;dr It's an instance of the original class. It has other data injected into so you avoid testing the injected parts and solely focus on testing the implementation details of your class/functions.

    Simple example:

    class Foo {
        func add (num1: Int, num2: Int) -> Int { // Line A 
            return num1 + num2 // Line B
        }
    }
    
    let unit = Foo() // unit under test
    assertEqual(unit.add(1,5),6)
    

    As you can see, I'm not testing LineA ie I'm not validating the input parameters. I'm not validating to see if num1, num2 are an Integer. I have no asserts against that.

    I'm only testing to see if LineB (my implementation) given the mocked values 1 and 5 is doing as I expect.

    Obviously in the real word this can become much more complex. The parameters can be a custom object like a Person, Address, or the implementation details can be more than a single +. But the logic of testing would be the same.

    Non-coding Example:

    Assume you're building a machine that identifies the type and brand name of electronic devices for an airport security. The machine does this by processing what it sees with its camera.

    Now your manager walks in the door and asks you to unit-test it.

    Then you as a developer you can either bring 1000 real objects, like a MacBook pro, Google Nexus, a banana, an iPad etc in front of it and test and see if it all works.

    But you can also use mocked objects, like an identical looking MacBook pro (with no real internal parts) or a plastic banana in front of it. You can save yourself from investing in 1000 real laptops and rotting bananas.

    The point is you're not trying to test if the banana is fake or not. Nor testing if the laptop is fake or not. All you're doing is testing if your machine once it sees a banana it would say not an electronic device and for a MacBook Pro it would say: Laptop, Apple. To the machine, the outcome of its detection should be the same for fake/mocked electronics and real electronics. If your machine also factored in the internals of a laptop (x-ray scan) or banana then your mocks' internals need to look the same as well. But you could also use a gadget with a friend motherboard. Had your machine tested whether or not devices can power on then well you'd need real devices.

    The logic mentioned above applies to unit-testing of actual code as well. That is a function should work the same with real values you get from real input (and interactions) or mocked values you inject during unit-testing. And just as how you save yourself from using a real banana or MacBook, with unit-tests (and mocking) you save yourself from having to do something that causes your server to return a status code of 500, 403, 200, etc (forcing your server to trigger 500 is only when server is down, while 200 is when server is up. It gets difficult to run 100 network focused tests if you have to constantly wait 10 seconds between switching over server up and down). So instead you inject/mock a response with status code 500, 200, 403, etc and test your unit/function with a injected/mocked value.

    Be aware:

    Sometimes you don't correctly mock the actual object. Or you don't mock every possibility. E.g. your fake laptops are dark, and your machine accurately works with them, but then it doesn't work accurately with white fake laptops. Later when you ship this machine to customers they complain that it doesn't work all the time. You get random reports that it's not working. It takes you 3 months of time to finally figure out that the color of fake laptops need to be more varied so you can test your modules appropriately.

    For a true coding example, your implementation may be different for status code 200 with image data returned vs 200 with image data not returned. For this reason it's good to use an IDE that provides code coverage e.g. the image below shows that your unit-tests don't ever go through the lines marked with brown.

    image source

    Real world coding Example:

    Let's say you are writing an iOS application and have network calls.Your job is to test your application. To test/identify whether or not the network calls work as expected is NOT YOUR RESPONSIBILITY . It's another party's (server team) responsibility to test it. You must remove this (network) dependency and yet continue to test all your code that works around it.

    A network call can return different status codes 404, 500, 200, 303, etc with a JSON response.

    Your app is suppose to work for all of them (in case of errors, your app should throw its expected error). What you do with mocking is you create 'imaginary—similar to real' network responses (like a 200 code with a JSON file) and test your code without 'making the real network call and waiting for your network response'. You manually hardcode/return the network response for ALL kinds of network responses and see if your app is working as you expect. (you never assume/test a 200 with incorrect data, because that is not your responsibility, your responsibility is to test your app with a correct 200, or in case of a 400, 500, you test if your app throws the right error)

    This creating imaginary—similar to real is known as mocking.

    In order to do this, you can't use your original code (your original code doesn't have the pre-inserted responses, right?). You must add something to it, inject/insert that dummy data which isn't normally needed (or a part of your class).

    So you create an instance the original class and add whatever (here being the network HTTPResponse, data OR in the case of failure, you pass the correct errorString, HTTPResponse) you need to it and then test the mocked class.

    Long story short, mocking is to simplify and limit what you are testing and also make you feed what a class depends on. In this example you avoid testing the network calls themselves, and instead test whether or not your app works as you expect with the injected outputs/responses —— by mocking classes

    Needless to say, you test each network response separately.


    Now a question that I always had in my mind was: The contracts/end points and basically the JSON response of my APIs get updated constantly. How can I write unit tests which take this into consideration?

    To elaborate more on this: let’s say model requires a key/field named username. You test this and your test passes. 2 weeks later backend changes the key's name to id. Your tests still passes. right? or not?

    Is it the backend developer’s responsibility to update the mocks. Should it be part of our agreement that they provide updated mocks?

    The answer to the above issue is that: unit tests + your development process as a client-side developer should/would catch outdated mocked response. If you ask me how? well the answer is:

    Our actual app would fail (or not fail yet not have the desired behavior) without using updated APIs...hence if that fails...we will make changes on our development code. Which again leads to our tests failing....which we’ll have to correct it. (Actually if we are to do the TDD process correctly we are to not write any code about the field unless we write the test for it...and see it fail and then go and write the actual development code for it.)

    This all means that backend doesn’t have to say: “hey we updated the mocks”...it eventually happens through your code development/debugging. ‌ّBecause it’s all part of the development process! Though if backend provides the mocked response for you then it's easier.

    My whole point on this is that (if you can’t automate getting updated mocked API response then) some human interaction is required ie manual updates of JSONs and having short meetings to make sure their values are up to date will become part of your process

    This section was written thanks to a slack discussion in our CocoaHead meetup group


    For iOS devs only:

    A very good example of mocking is this Practical Protocol-Oriented talk by Natasha Muraschev. Just skip to minute 18:30, though the slides may become out of sync with the actual video

    0 讨论(0)
  • 2020-11-22 03:56

    Mock is a method/object that simulates the behavior of a real method/object in controlled ways. Mock objects are used in unit testing.

    Often a method under a test calls other external services or methods within it. These are called dependencies. Once mocked, the dependencies behave the way we defined them.

    With the dependencies being controlled by mocks, we can easily test the behavior of the method that we coded. This is Unit testing.

    What is the purpose of mock objects?

    Mocks vs stubs

    Unit tests vs Functional tests

    0 讨论(0)
  • 2020-11-22 03:57

    The purpose of mocking types is to sever dependencies in order to isolate the test to a specific unit. Stubs are simple surrogates, while mocks are surrogates that can verify usage. A mocking framework is a tool that will help you generate stubs and mocks.

    EDIT: Since the original wording mention "type mocking" I got the impression that this related to TypeMock. In my experience the general term is just "mocking". Please feel free to disregard the below info specifically on TypeMock.

    TypeMock Isolator differs from most other mocking framework in that it works my modifying IL on the fly. That allows it to mock types and instances that most other frameworks cannot mock. To mock these types/instances with other frameworks you must provide your own abstractions and mock these.

    TypeMock offers great flexibility at the expense of a clean runtime environment. As a side effect of the way TypeMock achieves its results you will sometimes get very strange results when using TypeMock.

    0 讨论(0)
  • 2020-11-22 03:58

    If your mock involves a network request, another alternative is to have a real test server to hit. You can use a service to generate a request and response for your testing.

    0 讨论(0)
  • 2020-11-22 04:04

    Mocking is generating pseudo-objects that simulate real objects behaviour for tests

    0 讨论(0)
  • I would think the use of the TypeMock isolator mocking framework would be TypeMocking.

    It is a tool that generates mocks for use in unit tests, without the need to write your code with IoC in mind.

    0 讨论(0)
提交回复
热议问题