Mock——接口的部分方法使用已有实现,部分使用mock实现

           
           //mock设置默认值
            var requestMocService = new Mock<IRequestService>() ;
            requestMocService.DefaultValue = DefaultValue.Mock; //new RequestServiceClient(null);
            requestMocService.CallBase = true;
            //默认值的instance为真实实现
            requestMocService.DefaultValueProvider =new ZeroDefaultValueProvider<IRequestService>(new RequestServiceClient(null));
            requestMocService.Setup(n => n.SaveAccountIOInsertionRequest(It.IsAny<SaveAccountIOInsertionRequest>())).Returns(new SaveAccountIOInsertionResponse()
            {
                RequestId = 100
            });
             _services.AddSingleton(requestMocService.Object);


    
    class ZeroDefaultValueProvider<T> : DefaultValueProvider where T :class
    {
        T _instance;
        public ZeroDefaultValueProvider(T instance)
        {
            _instance = instance;
        }
        protected override object GetDefaultValue(Type type, Mock mock)
        {
            return type.IsValueType ? Activator.CreateInstance(type) : null;
        }
        //重写获取默认值的方法
        protected override object GetDefaultReturnValue(MethodInfo method, Mock mock)
        {
           // parameters[0].CopyTo(objEntity);

            // 1.Load(命名空间名称),GetType(命名空间.类名)
            // 3.调用的实例化方法(非静态方法)需要创建类型的一个实例
            //4.方法需要传入的参数
            // 5.调用方法,如果调用的是一个静态方法,就不需要第3步(创建类型的实例)
            // 相应地调用静态方法时,Invoke的第一个参数为null
            return method.Invoke(_instance, mock.Invocations[0].Arguments.ToArray());
        }
    }

  

Moq is a mocking framework for C#/.NET. It is used in unit testing to isolate your class under test from its dependencies and ensure that the proper methods on the dependent objects are being called. For more information on mocking you may want to look at the Wikipedia article on Mock Objects.

Other mocking frameworks (for .NET) include JustMockTypeMockRhinoMocksnMock, .etc.

Motivation

In a unit test, mock objects can simulate the behavior of complex, real objects and are therefore useful when a real object is impractical or impossible to incorporate into a unit test. If an object has any of the following characteristics, it may be useful to use a mock object in its place:

  • the object supplies non-deterministic results (e.g. the current time or the current temperature);
  • it has states that are difficult to create or reproduce (e.g. a network error);
  • it is slow (e.g. a complete database, which would have to be initialized before the test);
  • it does not yet exist or may change behavior;
  • it would have to include information and methods exclusively for testing purposes (and not for its actual task).

Technical details

Mock objects have the same interface as the real objects they mimic, allowing a client object to remain unaware of whether it is using a real object or a mock object. Many available mock object frameworks allow the programmer to specify which, and in what order, methods will be invoked on a mock object and what parameters will be passed to them, as well as what values will be returned. Thus, the behavior of a complex object such as a network socket can be mimicked by a mock object, allowing the programmer to discover whether the object being tested responds appropriately to the wide variety of states such mock objects may be in. 

Mocks, fakes, and stubs

Classification between mocks, fakes, and stubs is highly inconsistent across the literature.[1][2][3][4][5][6] Consistent among the literature, though, is that they all represent a production object in a testing environment by exposing the same interface.

Which out of mock, fake, or stub is the simplest is inconsistent, but the simplest always returns pre-arranged responses (as in a method stub). On the other side of the spectrum, the most complex object will fully simulate a production object with complete logic, exceptions, etc. Whether or not any of the mock, fake, or stub trio fits such a definition is, again, inconsistent across the literature.

For example, a mock, fake, or stub method implementation between the two ends of the complexity spectrum might contain assertions to examine the context of each call. For example, a mock object might assert the order in which its methods are called, or assert consistency of data across method calls.

In the book The Art of Unit Testing[7] mocks are described as a fake object that helps decide whether a test failed or passed by verifying whether an interaction with an object occurred. Everything else is defined as a stub. In that book, fakes are anything that is not real, which, based on their usage, can be either stubs or mocks

Setting expectations

Consider an example where an authorization subsystem has been mocked. The mock object implements an isUserAllowed(task : Task) : boolean[8] method to match that in the real authorization class. Many advantages follow if it also exposes an isAllowed : boolean property, which is not present in the real class. This allows test code easily to set the expectation that a user will, or will not, be granted permission in the next call and therefore readily to test the behavior of the rest of the system in either case.

Similarly, mock-only settings could ensure that subsequent calls to the sub-system will cause it to throw an exception, hang without responding, or return null etc. Thus it is possible to develop and test client behaviors for realistic fault conditions in back-end sub-systems as well as for their expected responses. Without such a simple and flexible mock system, testing each of these situations may be too laborious for them to be given proper consideration. 

Writing log strings

A mock database object's save(person : Person) method may not contain much (if any) implementation code. It might check the existence and perhaps the validity of the Person object passed in for saving (see fake vs. mock discussion above), but beyond that there might be no other implementation.

This is a missed opportunity. The mock method could add an entry to a public log string. The entry need be no more than "Person saved",[9]:146–7 or it may include some details from the person object instance, such as a name or ID. If the test code also checks the final contents of the log string after various series of operations involving the mock database then it is possible to verify that in each case exactly the expected number of database saves have been performed. This can find otherwise invisible performance-sapping bugs, for example, where a developer, nervous of losing data, has coded repeated calls to save() where just one would have sufficed. 

se in test-driven development

Programmers working with the test-driven development (TDD) method make use of mock objects when writing software. Mock objects meet the interface requirements of, and stand in for, more complex real ones; thus they allow programmers to write and unit-test functionality in one area without calling complex underlying or collaborating classes.[9]:144–5 Using mock objects allows developers to focus their tests on the behavior of the system under test without worrying about its dependencies. For example, testing a complex algorithm based on multiple objects being in particular states can be clearly expressed using mock objects in place of real objects.

Apart from complexity issues and the benefits gained from this separation of concerns, there are practical speed issues involved. Developing a realistic piece of software using TDD may easily involve several hundred unit tests. If many of these induce communication with databases, web services and other out-of-process or networked systems, then the suite of unit tests will quickly become too slow to be run regularly. This in turn leads to bad habits and a reluctance by the developer to maintain the basic tenets of TDD.

When mock objects are replaced by real ones, the end-to-end functionality will need further testing. These will be integration tests rather than unit tests. 

Limitations

The use of mock objects can closely couple the unit tests to the implementation of the code that is being tested. For example, many mock object frameworks allow the developer to check the order of and number of times that mock object methods were invoked by the real object being tested; subsequent refactoring of the code that is being tested could therefore cause the test to fail even though all mocked object methods still obey the contract of the previous implementation. This illustrates that unit tests should test a method's external behavior rather than its internal implementation. Over-use of mock objects as part of a suite of unit tests can result in a dramatic increase in the amount of maintenance that needs to be performed on the tests themselves during system evolution as refactoring takes place. The improper maintenance of such tests during evolution could allow bugs to be missed that would otherwise be caught by unit tests that use instances of real classes. Conversely, simply mocking one method might require far less configuration than setting up an entire real class and therefore reduce maintenance needs.

Mock objects have to accurately model the behavior of the object they are mocking, which can be difficult to achieve if the object being mocked comes from another developer or project or if it has not even been written yet. If the behavior is not modelled correctly then the unit tests may register a pass even though a failure would occur at run time under the same conditions that the unit test is exercising, thus rendering the unit test inaccurat

In Test-Driven Development by Example, Kent Beck also suggests the principle "Fake it till you make it". 

Keep the unit small

For TDD, a unit is most commonly defined as a class, or a group of related functions often called a module. Keeping units relatively small is claimed to provide critical benefits, including:

  • Reduced debugging effort – When test failures are detected, having smaller units aids in tracking down errors.
  • Self-documenting tests – Small test cases are easier to read and to understand.[8]

Effective layout of a test case ensures all required actions are completed, improves the readability of the test case, and smooths the flow of execution. Consistent structure helps in building a self-documenting test case. A commonly applied structure for test cases has (1) setup, (2) execution, (3) validation, and (4) cleanup.

  • Setup: Put the Unit Under Test (UUT) or the overall test system in the state needed to run the test.
  • Execution: Trigger/drive the UUT to perform the target behavior and capture all output, such as return values and output parameters. This step is usually very simple.
  • Validation: Ensure the results of the test are correct. These results may include explicit outputs captured during execution or state changes in the UUT.
  • Cleanup: Restore the UUT or the overall test system to the pre-test state. This restoration permits another test to execute immediately after this one.[8]

Practices to avoid, or "anti-patterns"

  • Having test cases depend on system state manipulated from previously executed test cases (i.e., you should always start a unit test from a known and pre-configured state).
  • Dependencies between test cases. A test suite where test cases are dependent upon each other is brittle and complex. Execution order should not be presumed. Basic refactoring of the initial test cases or structure of the UUT causes a spiral of increasingly pervasive impacts in associated tests.
  • Interdependent tests. Interdependent tests can cause cascading false negatives. A failure in an early test case breaks a later test case even if no actual fault exists in the UUT, increasing defect analysis and debug efforts.
  • Testing precise execution behavior timing or performance.
  • Building "all-knowing oracles". An oracle that inspects more than necessary is more expensive and brittle over time. This very common error is dangerous because it causes a subtle but pervasive time sink across the complex project.[11]
  • Testing implementation details.
  • Slow running tests.

Test-driven work

Test-driven development has been adopted outside of software development, in both product and service teams, as test-driven work.[25] Similar to TDD, non-software teams develop quality control (QC) checks (usually manual tests rather than automated tests) for each aspect of the work prior to commencing. These QC checks are then used to inform the design and validate the associated outcomes. The six steps of the TDD sequence are applied with minor semantic changes:

  1. "Add a check" replaces "Add a test"
  2. "Run all checks" replaces "Run all tests"
  3. "Do the work" replaces "Write some code"
  4. "Run all checks" replaces "Run tests"
  5. "Clean up the work" replaces "Refactor code"
  6. "Repeat"

Stub

I believe the biggest distinction is that a stub you have already written with predetermined behavior. So you would have a class that implements the dependency (abstract class or interface most likely) you are faking for testing purposes and the methods would just be stubbed out with set responses. They would not do anything fancy and you would have already written the stubbed code for it outside of your test.

Mock

A mock is something that as part of your test you have to setup with your expectations. A mock is not setup in a predetermined way so you have code that does it in your test. Mocks in a way are determined at runtime since the code that sets the expectations has to run before they do anything.

Difference between Mocks and Stubs

Tests written with mocks usually follow an initialize -> set expectations -> exercise -> verify pattern to testing. While the pre-written stub would follow an initialize -> exercise -> verify.

Similarity between Mocks and Stubs

The purpose of both is to eliminate testing all the dependencies of a class or function so your tests are more focused and simpler in what they are trying to prove.

According to Martin Fowler's article:

  • Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.
  • Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).
  • Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.
  • Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.
 

Foreword

There are several definitions of objects, that are not real. The general term is test double. This term encompasses: dummy, fake, stub, mock.

Reference

According to Martin Fowler's article:

  • Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.
  • Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).
  • Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.
  • Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

Style

Mocks vs Stubs = Behavioral testing vs State testing

Principle

According to the principle of Test only one thing per test, there may be several stubs in one test, but generally there is only one mock.

Lifecycle

Test lifecycle with stubs:

  1. Setup - Prepare object that is being tested and its stubs collaborators.
  2. Exercise - Test the functionality.
  3. Verify state - Use asserts to check object's state.
  4. Teardown - Clean up resources.

Test lifecycle with mocks:

  1. Setup data - Prepare object that is being tested.
  2. Setup expectations - Prepare expectations in mock that is being used by primary object.
  3. Exercise - Test the functionality.
  4. Verify expectations - Verify that correct methods has been invoked in mock.
  5. Verify state - Use asserts to check object's state.
  6. Teardown - Clean up resources.

Summary

Both mocks and stubs testing give an answer for the question: What is the result?

Testing with mocks are also interested in: How the result has been achieved?

Here's a description of each one followed by with real world sample.

  • Dummy - just bogus values to satisfy the API.

    Example: If you're testing a method of a class which requires many mandatory parameters in a constructor which have no effect on your test, then you may create dummy objects for the purpose of creating new instances of a class.

  • Fake - create a test implementation of a class which may have a dependency on some external infrastructure. (It's good practice that your unit test does NOT actually interact with external infrastructure.)

    Example: Create fake implementation for accessing a database, replace it with in-memory collection.

  • Stub - override methods to return hard-coded values, also referred to as state-based.

    Example: Your test class depends on a method Calculate() taking 5 minutes to complete. Rather than wait for 5 minutes you can replace its real implementation with stub that returns hard-coded values; taking only a small fraction of the time.

  • Mock - very similar to Stub but interaction-based rather than state-based. This means you don't expect from Mock to return some value, but to assume that specific order of method calls are made.

    Example: You're testing a user registration class. After calling Save, it should call SendConfirmationEmail.

Stubs and Mocks are actually sub types of Mock, both swap real implementation with test implementation, but for different, specific reasons.

In the codeschool.com course, Rails Testing for Zombies, they give this definition of the terms:

Stub

For replacing a method with code that returns a specified result.

Mock

A stub with an assertion that the method gets called.

So as Sean Copenhaver described in his answer, the difference is that mocks set expectations (i.e. make assertions, about whether or how they get called).

 

Stubs don't fail your tests, mock can.

 

I think the simplest and clearer answer about this question is given from Roy Osherove in his book The art of Unit Testing (page 85)

The easiest way to tell we’re dealing with a stub is to notice that the stub can never fail the test. The asserts the test uses are always against the class under test.

On the other hand, the test will use a mock object to verify whether the test failed or not. [...]

Again, the mock object is the object we use to see if the test failed or not.

That means if you are making assertions against the fake it means you are using the fake as a mock, if you are using the fake only to run the test without assertion over it you are using the fake as a stub.

Reading all the explanations above, let me try to condense:

  • Stub: a dummy piece of code that lets the test run, but you don't care what happens to it.
  • Mock: a dummy piece of code, that you VERIFY is called correctly as part of the test.
  • Spy: a dummy piece of code, that intercepts some calls to a real piece of code, allowing you to verify calls without replacing the entire original object.
 

If you compare it to debugging:

Stub is like making sure a method returns the correct value

Mock is like actually stepping into the method and making sure everything inside is correct before returning the correct value.

 

You can get some information :

From Martin Fowler about Mock and Stub

Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production

Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.

Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

From xunitpattern:

Fake: We acquire or build a very lightweight implementation of the same functionality as provided by a component that the SUT depends on and instruct the SUT to use it instead of the real.

Stub : This implementation is configured to respond to calls from the SUT with the values (or exceptions) that will exercise the Untested Code (see Production Bugs on page X) within the SUT. A key indication for using a Test Stub is having Untested Code caused by the inability to control the indirect inputs of the SUT

Mock Object that implements the same interface as an object on which the SUT (System Under Test) depends. We can use a Mock Object as an observation point when we need to do Behavior Verification to avoid having an Untested Requirement (see Production Bugs on page X) caused by an inability to observe side-effects of invoking methods on the SUT.

Personally

I try to simplify by using : Mock and Stub. I use Mock when it's an object that returns a value that is set to the tested class. I use Stub to mimic an Interface or Abstract class to be tested. In fact, it doesn't really matter what you call it, they are all classes that aren't used in production, and are used as utility classes for testing.

参考资料:

https://github.com/Moq/moq4

 Mocks Aren't Stubshttps://martinfowler.com/articles/mocksArentStubs.html

http://www.nudoq.org/#!/Packages/Moq/Moq/MockBehavior

http://www.nudoq.org/#!/Packages/Moq/Moq/DefaultValue

The Art of Unit Testing:https://en.wikipedia.org/wiki/The_Art_of_Unit_Testing

Test-driven development:https://en.wikipedia.org/wiki/Test-driven_development

Method stub:https://en.wikipedia.org/wiki/Method_stub

Stubs and Mocks:https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ff798400(v=pandp.10)?redirectedfrom=MSDN

What's the difference between a mock & stub?:https://stackoverflow.com/questions/3459287/whats-the-difference-between-a-mock-stub?lq=1

What's the difference between faking, mocking, and stubbing?:https://stackoverflow.com/questions/346372/whats-the-difference-between-faking-mocking-and-stubbing

 

 

 

原文地址:https://www.cnblogs.com/panpanwelcome/p/12467533.html