1
def generate_file(config: dict): -> None:
    ...
    my_obj = create_my_obj(config)
    my_obj_binary = my_obj.export()
    write_file(my_obj_binary, "some_path", mode="wb")

def create_my_obj(config: dict) -> MyObj:
   # some configuration checking etc.
   ...
   ...
   
   return MyObj(opt1="something", opt2="something_else", value="VALUE_TO_MOCK")


# TEST
def test_my_obj():
   config = ... # get config data from json or whatever...

   generate_file(config)
   
   # load a golden sample binary
   ...
   # load binary generated by my file
   ...

   # compare those two
   assert golden_sample_binary == generated_binary

Above is a snippet of my code I'm testing. My code generates a binary file and I need to compare this binary file with a golden sample to test, whether my code generates the file properly. I need to "mock" one input argument to a very specific value in MyObj() invoked in create_my_obj(). I'm using unittest library, unfortunately I'm not able to figure this out.

Thanks for any hints

6
  • When you say I need to "mock" one input argument to a very specific value in MyObj() invoked in create_my_obj() By value do you just mean mock an attribute? if so you can do an arbitrary assignment to the attribute using MyObj.attribute = "value" inline Commented Aug 23, 2021 at 5:09
  • From "test_my_obj( )" I don't have access to "MyObj" class to be able to do so. By default MyObj( ) set's "value" to None, whereas I need it to be let's say '1234'. I could do what you propose in "create_my_obj", but that would modify my code permanently, not just for testing. Commented Aug 23, 2021 at 5:15
  • I see, so my_obj is being serialized and then you are checking the file in the test. If you know what value should be you can add a line after my_obj = create_my_obj(config) that just has my_obj.value = "1234" which means it will be baked into the export for you. Commented Aug 23, 2021 at 5:18
  • Still the same problem, generate_file( ) can't be modified this way, as it's part of the "API" to say. I need to do it from test_my_obj. So my idea was, "redefine" MyObj in a way, where value wouldn't be None by default, but '1234' and I thought mocking MyObj could work, but can't figure out how. Commented Aug 23, 2021 at 5:23
  • I see, you can use mock objects with the mock library (docs.python.org/3/library/unittest.mock.html#the-mock-class). I haven't done it with a class so I unfortunately can't help you, but it's probably the right place to start looking. Otherwise the Patch the function's __defaults__ attribute section of this article might help mdawar.dev/blog/mock-python-default-function-argument Commented Aug 23, 2021 at 5:28

1 Answer 1

1

So based on @Kiearan Wood link, the solution is to patch the defaults of the init method using mock.patch.object.

import unittest.mock as mock

def test_my_obj():
   config = ... # get config data from json or whatever...

   new_defaults = list(MyObj.__init__.__defaults__)
   # The value to mock is the last in the list...
   new_defaults[-1] = "value to mock"
   new_defaults = tuple(new_defaults)

   with mock.patch.object(MyObj.__init__, "__defaults__", new_defaults):
       generate_file(config)
   
   # load a golden sample binary
   ...
   # load binary generated by my file
   ...

   # compare those two
   assert golden_sample_binary == generated_binary

Thank you very much for the link, which helped a lot!! :-)

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.