Mocking Communications

I am creating an application in python that uses a wrapper in a library that does hardware communication

I would like to create some test units, and I am fairly new to unit tests, so I would like to poke fun at the posts, but I really don’t know how.

quick example:

this is the application code using comm lib

def changeValue(id, val):
    current_value = comm.getval(id)
    if (current_value != val):
        comm.send(id, val)

      

I want to test this without doing any communication i.e. replacing comm.getval's return with some mock value and sending comm.send to the generated comm class.

Can anyone tell me this?


The point is that comm is an object inside a class

let's say the class is like this:

class myClass:
    comm = Comm()
    ....
    def __init__():
        comm = comm.start()

    def changeValue(id, val):
        ....

    ....

      

+3


source to share


2 answers


You can use the mock

framework for this kind of job. First of all, you are using comm = Comm()

in MyClass

, which means that you have something like from comm_module import Comm

in a module MyClass

. In these cases, you need to correct the link Comm

in the module MyClass

to make the patch active.

So an example of how you can test your code without any connection could be:



@patch("my_class.Comm", autospec=True)
def test_base(self, mock_comm_factory):
    mock_comm = mock_comm_factory.return_value
    MyClass()
    mock_comm.start.assert_called_with()

@patch("my_class.Comm", autospec=True)
def test_changeValue(self, mock_comm_factory):
    mock_comm = mock_comm_factory.return_value
    mock_comm.getval.return_value = 13
    MyClass().changeValue(33, 23)
    mock_comm.getval.assert_called_with(33)
    mock_comm.send.assert_called_with(33, 23)
    mock_comm.reset_mock()
    mock_comm.getval.return_value = 23
    MyClass().changeValue(33, 23)
    mock_comm.getval.assert_called_with(33)
    self.assertFalse(mock_comm.send.called)

      

Now I can start to explain all the details of my answer like why to use autospec=True

or how to apply the patch for all methods , but that means rewriting a lot of mock

SO docs and answers. So I hope this is enough as a starting point.

+2


source


The trick is not to use global objects like comm

. If possible, make it comm

injected by your class or method by the caller. Then what you do is convey mocking comm

when testing, and then real when building.

Thus, either you create a link comm

in your class field (and inject it using a constructor or setter method) like so:

class myClass:

  ....
  def __init__(myComm):
    comm = myComm;
    comm = comm.start()

  def changeValue(id, val):
    current_value = comm.getval(id)
    if (current_value != val):
      comm.send(id, val)

....

      

or you will make it a parameter in the method in which it is used, like



def changeValue(id, val, myComm):
current_value = myComm.getval(id)
if (current_value != val):
    myComm.send(id, val)

      

Using globally nothing mocks is a huge pain, try to use Dependency Injection when you need to mock something.

This is another good article on DI. It's in java, but it should be the same in python http://googletesting.blogspot.ca/2008/07/how-to-think-about-new-operator-with.html

+1


source







All Articles