Sometimes there are functions that return complicated data and cannot be divided any further e.g. in the area of signal processing or when reading and decoding a bytestring to another format. How am I supposed to create stubs (e.g. the bytestring) to be able to assert equality of expected data with the return data without getting into trouble with complicated stub generation?
In the following example I want to test two functions. One writes my_package-objects to disk and the other reads them from disk into an object dictionary. The open
-dependency is mocked away. How can I define the stub_binary()
-function?
def read(filename):
"""Read any compatible my_package objects from disk."""
with open(filename, 'rb') as f:
return _decode(f.read())
def write(filename, **objs):
"""Write any compatible my_package objects to disk."""
with open(filename, 'wb') as f:
f.write(_encode(objs))
import my_package as mp
@patch('my_package.open', new_callable=mock_open)
def test_read(m_open):
# arrange
m_enter = m_open.return_value.__enter__.return_value
m_enter.read.side_effect = lambda: stub_binary()
# act
obj_dict = mp.read('./obj_A_and_B')
# assert
assert obj_dict == {'A': A(), 'B': B()}
@patch('my_package.open', new_callable=mock_open)
def test_write(m_open):
# arrange
m_enter = m_open.return_value.__enter__.return_value
# act
mp.write('./obj_A_and_B', A=A(), B=B())
# assert
m_enter.write.assert_called_with(stub_binary())
- Stub_binary could return a hard-coded bytestring, but that gets easily messy:
def stub_binary():
return (
b'\x93NUMPY\x01\x00v\x00{"descr": "<f8", "fortran_order": False, '
b'"shape": (1, 3), } '
b' \n\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00'
b'\x00\x00@\x00\x00\x00\x00\x00\x00\x08@')
- Or reading the above byte string from a file that was generated with mp.write:
def stub_binary():
with open(gen_data, 'rb') as f:
return f.read()
- Or just replace
stub_binary()
with the following:
def stub_binary(x):
with io.BytesIO() as buffer:
mp.write(buffer, A=A(), B=B())
return buffer
I am tempted to create the data with my production code mp.write()
. But this seems not right to me. How would you approach this?