Mocking input using python wrapped c ++ swig

I am new to switt and python unittesting.

Here is what I am trying to do. I have a C ++ function that requires user input. C ++ code exits into python code using SWIG. I am trying to use the unittest pythons module to mock input. Ive tried a mocking inline function and wrote my own core function in C ++, which simply returns a string and taunts it.

Mocking builtins.input still freezes when I get to std :: cin in C ++ code. and makes fun of a function that returns a string, does not return the mocked value of return_value.

My guess is, for some reason, I cannot scoff at the return value of a function, because it is really C ++ code, not a true python.

Here is an example of the code I'm working with:

C ++ I can include a header file, but its very simple.

#include "MockTest.h" #include <iostream> #include <string> MockTest::MockTest() {} std::string MockTest::getInput() { std::string name; std::cout << "Enter you name" << std::endl; name = this->mockInput("hi"); //std::cin >> name; std::string toReturn = "Hello " + name + " person"; return toReturn; } std::string MockTest::mockInput(std::string input) { return input; } 

swig interface file:

 %module MockTest %include "std_string.i" %include "std_vector.i" %include "std_iostream.i" %{ #include "MockTest.h" %} %include <MockTest.h> 

python script test

 from unittest.mock import patch from unittest import TestCase import unittest import MockTest class Test(TestCase): @patch('builtins.input', return_value="Will") def test_Mocktest(self, input): self.assertEqual(MockTest.MockTest().getInput(), 'Hello Will person') @patch('MockTest.MockTest.mockInput', return_value="Will") def test_Mocktest2(self, mockInput): self.assertEqual(MockTest.MockTest().getInput(), 'Hello Will person') if __name__ == '__main__': unittest.main() 
+5
source share
1 answer

After spending some time, of which ~ one hour for a stupid mistake:

  • The fact that the generated module was incomplete (the linker did not complain about undefined characters when it did not deliver the MockTest object to it)
  • It was eventually created because I forgot to add public: in front of class members in MockTest.h ... X: ((((

and for some time, exploring the real problem, I finally came to the conclusion: the problem is not that the C ++ language (at least not directly), but lies in the intermediate layer (s) created by Swig .

More details

The MockTest class (the return method of the mockInput method that we are trying to patch ) is defined in the MockTest module ( !!!, which is MockTest.py !!! ), which is automatically generated by Swig (the command in my case was swig -o MockTest_wrap.cpp -python -c++ MockTest.i ). Here is its definition:

 class MockTest(_object): __swig_setmethods__ = {} __setattr__ = lambda self, name, value: _swig_setattr(self, MockTest, name, value) __swig_getmethods__ = {} __getattr__ = lambda self, name: _swig_getattr(self, MockTest, name) __repr__ = _swig_repr def __init__(self): this = _MockTest.new_MockTest() try: self.this.append(this) except __builtin__.Exception: self.this = this __swig_destroy__ = _MockTest.delete_MockTest __del__ = lambda self: None def getInput(self): return _MockTest.MockTest_getInput(self) def mockInput(self, input): return _MockTest.MockTest_mockInput(self, input) 

As you probably guessed, this mockInput is patch ed, not the one from C ++ (whose name is MockTest_mockInput and exported by its own module: _MockTest - the proper name _wrap_MockTest_mockInput defined in MocTest_wrap.cpp). Of course, since getInput calls MockTest_getInput , patch ing mockInput (the Python shell) has no effect (just as if you changed its body to say: return "123" ).

Here is an example of the code I prepared to better illustrate the behavior (as I mentioned in my comment, I am using Python 3.5.4). Please ignore the last 3 lines of code and output them until you read the following paragraph:

 from unittest.mock import patch import MockTest if __name__ == "__main__": return_value = "value overridden by `patch`" mock_input_arg = "argument passed to `MockTest.mockInput`" mock_test = MockTest.MockTest() with patch("MockTest.MockTest.mockInput", return_value=return_value): print("`mock_test.getInput()` returned: \"{}\"".format(mock_test.getInput())) print("`mock_test.mockInput(\"{}\")` returned: \"{}\"".format(mock_input_arg, mock_test.mockInput(mock_input_arg))) print("\nDon't mind the following output for now...\n") # SAME THING about the following code with patch("MockTest._MockTest.MockTest_mockInput", return_value=return_value): print("`mock_test.getInput()` returned: \"{}\"".format(mock_test.getInput())) print("`mock_test.mockInput(\"{}\")` returned: \"{}\"".format(mock_input_arg, mock_test.mockInput(mock_input_arg))) 

And the conclusion:

 c:\Work\Dev\StackOverflow\q45934545>"c:\Install\x64\Python\Python\3.5\python.exe" dummy.py Enter you name `mock_test.getInput()` returned: "Hello hi person" `mock_test.mockInput("argument passed to `MockTest.mockInput`")` returned: "value overridden by `patch`" Don't mind the following output for now... Enter you name: `mock_test.getInput()` returned: "Hello hi person" `mock_test.mockInput("argument passed to `MockTest.mockInput`")` returned: "value overridden by `patch`" 

Then I went on trying patch MockTest._MockTest.MockTest_mockInput , but I got the same result because I did not patch MockTest::mockInput (from MockTest.cpp), but _wrap_MockTest_mockInput (from MocTest_wrap.cpp).

Below is a table with all the layers between C ++ and Python code for mockInput (for getInput it is exactly the same):

mockInput layers

As getInput calls mockInput ( layer 0 ), there should be a patch , but, unfortunately, is not available for Python.

The 1 st solution that comes to my mind is to patch ing getInput (layer 1) directly (if used in many places).

+1
source

Source: https://habr.com/ru/post/1271321/


All Articles