Reputation: 3
My code looks somewhat like this:
def write_wallet_file_entry(name, value, wallet_file, wallet_password):
some_code
some_more_code_to_write_to_the_wallet
...
I am using Python (2.6) and using unittest module for unit testing this code. Code creates the wallet file, if it does not exist and then writes a bunch of key value pairs to it.
Once I write to the wallet, there is no text parsing I can do to confirm that the write was clean.
CLARIFICATION: Stating the NOT SO obvious: I cannot use "unittest.mock" or "mock" module which would have made the problem simpler to solve. My environment is stuck on python 2.6, does not have "virtualenv", does not have "mock" module and does not allow installation of external modules on the system.
Any suggestions would be really helpful.
Upvotes: 0
Views: 233
Reputation: 9846
These assumptions won't change the gist of my answer, but they will mean we can be clear about terminology, since you haven't posted a Minimum, Complete and Verifiable Example.
A 'wallet file' is literally a file-like object. It obeys the same semantics as a file stream object, for which Python's open()
is a direct wrapper.
Only the wallet_file
and wallet_password
are wallet file-specific. name
and value
are a key-value pair you seek to pass in to the file.
Your problem here is in being able to test that your writes are 'clean'.
However, you don't need to check if the file was written to correctly or if it was created -
you'd only be testing Python's file
object that way, which is pretty robustly tested already.
The point of unit tests is to test code you've written, not external services. It should always be assumed that the external service did its job in unit tests - you only test the external service in an integration test.
What you need is a way to ensure that the values you sent to be written were correctly received and not garbled, and that your request to create a file was received in the format you wanted. Test the message, not the recipient.
One technique is to abstract your input as a class, and subclass it to have dummy methods. You can then use the subclass as a glorified mock, for all intents and purposes.
In other words, change
def write_wallet_file_entry(name, value, wallet_file, wallet_password):
...
to
class Wallet(object):
def __init__(self, wallet_file, wallet_password):
self.file = wallet_file
self.password = wallet_password
def exists(self):
# code to check if file exists in filesystem
def write(self, name, value):
# code to write name, value
def write_wallet_file_entry(name, value, WalletObject):
assert isinstance(WalletObject, Wallet), "Only Wallets allowed"
if WalletObject.exists():
WalletObject.write(name, value)
To test, you can now create MockWallet
:
class MockWallet(Wallet):
def __init__(self, wallet_file, wallet_password):
super(MockWallet, self).__init__(wallet, wallet_password)
self.didCheckExists = False
self.didAttemptWrite = False
self.didReceiveCorrectly = False
def exists(self):
super(MockWallet, self).exists()
self.didCheckExists = True
def write(self, name, value):
# ... some code to validate correct arguments were pass
self.didReceiveCorrectly = True
if super(MockWallet, self).write(name, value):
self.didAttemptWrite = True
Now you can use the same function in production (just pass a Wallet
!) and in tests (just pass a MockWallet
and check against attributes of that object!):
import unittest
from ... import MockWallet, write_wallet_file_entry
class Test(unittest.TestCase):
def testWriteFlow(self):
mock = MockWallet()
name, value = 'random', 'more random'
write_wallet_file_entry(name, value, mock)
self.assertTrue(mock.didCheckExists)
self.assertTrue(mock.didAttemptWrite)
self.assertTrue(mock.didReceiveCorrectly)
Voila! You now have a tested write flow with a handily-improvised mock using nothing more than dependency injection instead of arbitrary function parameters.
Upvotes: 1