fake/mock nonvirtual C++ methods

后端 未结 8 1634
谎友^
谎友^ 2020-12-13 19:32

It known that in C++ mocking/faking nonvirtual methods for testing is hard. For example, cookbook of googlemock has two suggestion - both mean to modify original source code

相关标签:
8条回答
  • 2020-12-13 20:04

    @zaharpopov you can use Typemock IsolatorPP to create mocks of non-virtual class and methods without changing your code (or legacy code). for example if you have a non-virtual class called MyClass:

    class MyClass
    {
     public:
       int GetResult() { return -1; }
    }
    

    you can mock it with typemock like so:

    MyClass* fakeMyClass = FAKE<MyClass>();
    WHEN_CALLED(fakeMyClass->GetResult()).Return(10);
    

    By the way the classes or methods that you want to test can also be private as typemock can mock them too, for example:

    class MyClass
    {
    private:
       int PrivateMethod() { return -1; }
    }
    
    
    MyClass* myClass =  new MyClass();
    
    PRIVATE_WHEN_CALLED(myClass, PrivateMethod).Return(1);
    

    for more information go here.

    0 讨论(0)
  • 2020-12-13 20:07

    Code has to be written to be testable, by whatever test techniques you use. If you want to test using mocks, that means some form of dependency injection.

    Non-virtual calls with no dependence on a template parameter pose the same problem as final and static methods in Java[*] - the code under test has explicitly said, "I want to call this code, not some unknown bit of code that's dependent in some way on an argument". You, the tester, want it to call different code under test from what it normally calls. If you can't change the code under test then you, the tester, will lose that argument. You might as well ask how to introduce a test version of line 4 of a 10-line function without changing the code under test.

    If the class to be mocked is in a different TU from the class under test, you can write a mock with the same name as the original and link that instead. Whether you can generate that mock using your mocking framework in the normal way, I'm not so sure.

    If you like, I suppose it's a "very bad problem for C++" that it's possible to write code that's hard to test. It shares this "problem" with a great number of other languages...

    [*] My Java knowledge is quite low-power. There may be some clever way of mocking such methods in Java, which aren't applicable to C++. If so, please disregard them in order to see the analogy ;-)

    0 讨论(0)
  • 2020-12-13 20:07

    I think it is not possible to do it with standard C++ right now (but lets hope that a powerful compile-time reflection will come to C++ soon...). However, there are a number of options for doing so.

    You might have a look at Injector++. It is Windows only right now, but plans to add support for Linux & Mac.

    Another option is CppFreeMock, which seems to work with GCC, but has no recent activities.

    HippoMocks also provide such ability, but only for free functions. It doesn't support it for class member functions.

    I'm not completely sure, but it seems that all the above achieve this with overwriting the target function at runtime so that it jumps to the faked function.

    The there is C-Mock, which is an extension to Google Mock allowing you to mock non-virtual functions by redefining them, and relying on the fact that original functions are in dynamic libraries. It is limited to GNU/Linux platform.

    Finally, you might also try PowerFake (for which, I'm the author) as introduced here.

    It is not a mocking framework (currently) and it provides the possibility for replacing production functions with test ones. I hope to be able to integrate it to one or more mocking frameworks; if not, it'll become one. **Update: ** It has an integration with FakeIt.

    It also overrides the original function during linking (so, it won't work if a function is called in the same translation unit in which it is defined), but uses a different trick than C-Mock as it uses GNU ld's --wrap option. It also needs some changes to your build system for tests, but doesn't affect the main code in any way (except if you are forced to put a function in a separate .cpp file); but support for easily integrating it into CMake projects is provided.

    But, it is currently limited to GCC/GNU ld (works also with MinGW).

    0 讨论(0)
  • 2020-12-13 20:14

    One way that we sometimes use is to split the original .cpp file into at least two parts.

    Then the test apparatus can supply its own implementations; effectively using the linker to do the dirty work for us.

    This is called the "Link Seam" in some circles.

    0 讨论(0)
  • 2020-12-13 20:16

    You very specifically say "if you can't modify original code", which the techniques you mention in your question (and all the other current "answers") do.

    Without changing that source, you can still generally (for common OSes/tools) preload an object that defines its own version of the function(s) you wish to intercept. They can even call the original functions afterwards. I provided an example of doing this in (my) question Good Linux TCP/IP monitoring tools that don't need root access?.

    0 讨论(0)
  • 2020-12-13 20:16

    I used to create an interface for the parts I needed to mock. Then I simply created a stub class that derived from this interface and passed this instance to my classes under test. Yes, it is a lot of hard work, but I found it worth it for some circumstances.

    Oh, by interface I mean a struct with only pure virtual methods. Nothing else!

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