The Purpose of Mocking

和自甴很熟 提交于 2019-11-30 05:42:42

The purpose of mocking is to isolate the class being tested from other classes.

This is helpful when a class :

  • connects to an external resource (FileSystem, DB, network ... )
  • is expensive to setup, or not yet available (hardware being developed)
  • slows down the execution of the unit tests
  • has a non-deterministic behavior
  • has (or is) a user interface

It also makes it easier to test for error conditions, as your build your mock object so that it returns and error, throw an exception ...

The mock can record how it was invoked (function calls order, parameters) and this can be verified by the test. EDIT: For instance: The method you're testing sends a message, such as an IPC. The method of the mock object can record how many times it was invoked, the parameter he received (i.e. the message to be sent). Then the test can interrogate the mock object and assert on the number of messages sent, the content of the message ... Likewise, the mock object can record the methods that are called in a log string and the test can retrieve that string and assert on it.

Do not abuse of mock objects: test the behaviour rather than the implementation, or the unit tests will be too tightly coupled to the code, and brittle (break at refactoring).

Mock can be coded manually, or generated by a mocking framework.

Mocking allows you to isolate your class under test from its dependencies. Generally, you create a mock for each dependency for the class under test and set up the mock to return expected values. You then provide the mock to your class under test instead of a real copy of the class that your class under test is dependent on. You can then use the mocking framework to check that the expected calls were made to the mock object(s) to ensure that your class under test is operating correctly.

Its designed to poke fun at an individual instance from a group collection. Used a lot at irregular object gatherings.

While mocking is usually understood as allowing for isolation of a class under test this isn't the main point of a mock (stubs are better for this). Instead we need to look at what happens when an object is told to do something which is one of 3 things..

  1. Direct Output - result of a method call
  2. Internal Changes - changes to the class during a method call
  3. Indirect Output - code under test calls a different class

State based testing is all about #1 and #2. #1 via looking at the result that the method gives you. #2 by accessing the objects internal state.

This leaves us with #3 for which there are two avenues we can take. The first is a by using a Mock and the second by using a Test Spy. The main difference is that on a Mock you create the expectations before executing the code under test and then have the mock verify them after, whereas with a Test Spy you execute the code under test and then ask the Test Spy if certain actions occurred.

So to sum all that up.. when you think about testing what a class does if you need to test indirect output (aka a call to another class) that is where Mocking comes into play.

I'm new to mocking as well but I'll take a stab at this. In my experience mocking has two main benefits:

  • You can start working with objects before actually writing the implementation. You can define an interface and use mocking to work with the interface in unit tests or even code.
  • Mocking allows you to isolate the object under test in unit tests. With mock objects, you can completely control any objects that the object under test interacts with, therefore removing external dependencies from the test.

"Mock" is a heavily overloaded term in testing & TDD circles. See Martin Fowler's article Mocks Aren't Stubs. A "proper" mock knows what values it's supposed to receive and lets you know when it doesn't get what was intended; this allows you to do interaction testing instead of state testing - you verify that the class under test is passing the correct messages to its collaborators, in the correct sequence. Interaction testing is quite different from conventional state testing and can be hard to get your head around. Keeping in mind that interaction testing is the point of mocks may make them easier to understand.

Umar Abbas

Great Realtime Example of Mocking by Bert F

Unit Testing

Imagine unit testing for this system:

cook <- waiter <- customer

Its generally easy to envision testing a low-level component like the cook:

cook <- test driver

The test driver simply orders different dishes and verifies the cook returns the correct dish for each order.

Its harder to test a middle component, like the waiter, that utilizes the behavior of other components. A naive tester might test the waiter component the same way we tested the cook component:

cook <- waiter <- test driver

The test driver would order different dishes and ensure the waiter returns the correct dish. Unfortunately, that means that this test of the waiter component may be dependent on the correct behavior of the cook component. This dependency is even worse if the cook component has any test-unfriendly characteristics, like non-deterministic behavior (the menu includes chef's surprise as an dish), lots of dependencies (cook won't cook without his entire staff), or lot of resources (some dishes require expensive ingredients or take an hour to cook).

Since this a waiter test, ideally, we want to test just the waiter, not the cook. Specifically, we want to make sure the waiter conveys the customer's order to the cook correctly and delivers the cook's food to the customer correctly.

Unit testing means testing units independently, so a better approach would be to isolate the component under test (the waiter) using what Fowler calls test doubles (dummies, stubs, fakes, mocks).

    -----------------------
   |                       |
   v                       |
test cook <- waiter <- test driver

Here, the test cook is "in cahoots" with the test driver. Ideally, the system under test is designed so that the test cook can be easily substituted (injected) to work with the waiter without changing production code (e.g. without changing the waiter code).

Mock Objects

Now, the test cook (test double) could be implemented different ways:

  • a fake cook - a someone pretending to be a cook by using frozen dinners and a microwave,
  • a stub cook - a hot dog vendor that always gives you hot dogs no matter what you order, or
  • a mock cook - an undercover cop following a script pretending to be a cook in a sting operation.

See Fowler's article for the more specifics about fakes vs stubs vs mocks vs dummies, but for now, let's focus on a mock cook.

    -----------------------
   |                       |
   v                       |
mock cook <- waiter <- test driver

A big part of unit testing the waiter component focuses on how the waiter interacts with the cook component . A mock-based approach focuses on fully specifying what the correct interaction is and detecting when it goes awry.

The mock object knows in advance what is supposed to happen during the test (e.g. which of its methods calls will be invoked, etc.) and the mock object knows how it is supposed to react (e.g. what return value to provide). The mock will indicate whether what really happens differs from what is supposed to happen. A custom mock object could be coded for the expected behavior of each test case, but a mocking framework strives to allow such a behavior specification to be clearly and easily indicated directly in the test case.

The conversation surrounding a mock-based test might look like this:

test driver to mock cook: expect a hot dog order and give him this dummy hot dog in response

test driver (posing as customer) to waiter: I would like a hot dog please
waiter to mock cook: 1 hot dog please
mock cook to waiter: order up: 1 hot dog ready (gives dummy hot dog to waiter)
waiter to test driver: here is your hot dog (gives dummy hot dog to test driver)

test driver: TEST SUCCEEDED!

But since our waiter is new, this is what could happen:

test driver to mock cook: expect a hot dog order and give him this dummy hot dog in response

test driver (posing as customer) to waiter: I would like a hot dog please
waiter to mock cook: 1 hamburger please
mock cook stops the test: I was told to expect a hot dog order!

test driver notes the problem: TEST FAILED! - the waiter changed the order

or

test driver to mock cook: expect a hot dog order and give him this dummy hot dog in response

test driver (posing as customer) to waiter: I would like a hot dog please
waiter to mock cook: 1 hot dog please
mock cook to waiter: order up: 1 hot dog ready (gives dummy hot dog to waiter)
waiter to test driver: here is your french fries (gives french fries from some other order to test driver)

test driver notes the unexpected french fries: TEST FAILED! the waiter gave back wrong dish

It may be hard to clearly see the difference between mock objects and stubs without a contrasting stub-based example to go with this, but this answer is way too long already :-)

Also note that this is a pretty simplistic example and that mocking frameworks allow for some pretty sophisticated specifications of expected behavior from components to support comprehensive tests. There's plenty of material on mock objects and mocking frameworks for more information.

MatthieuGD

One other answer :

  • Stub = fake objects to be able to run your test without the entire real context

  • Mock = fake object to record the interaction of your component and verify theses interactions

You can have several stubs in one test but only one mock because if you have more than one mock you certainly test more than one feature (and it defeat the purpose of the test-one-thing principle).

To go beyond the basics, Mocks are more behavioral verification than the traditionnal state verification of the test where you check the state of your component after acting on it (Arrange,Act, Assert with Mocks it is more Arrange, Act, Verify) :

State verification Assert.AreEqual(valueExpected,mycomponent.Property); Behavioral verification : myMock.WasCalled(MyMethod);

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!