对写入加密钱包文件的函数或方法进行单元测试的正确方法是什么?
What is the correct way to unit test a function or method that writes to an encrypted wallet file?
我的代码看起来有点像这样:
def write_wallet_file_entry(name, value, wallet_file, wallet_password):
some_code
some_more_code_to_write_to_the_wallet
...
我正在使用 Python (2.6) 并使用 unittest 模块对此代码进行单元测试。代码创建钱包文件,如果它不存在然后写入一堆键值对。
一旦我写入钱包,就无法进行文本解析来确认写入是干净的。
澄清:说明不那么明显:我不能使用 "unittest.mock" 或 "mock" 模块,这会使问题更容易解决。我的环境卡在 python 2.6,没有 "virtualenv",没有 "mock" 模块,并且不允许在系统上安装外部模块。
任何建议都会很有帮助。
一些假设
这些假设不会改变我回答的要点,但它们意味着我们可以清楚地了解术语,因为您还没有发布 Minimum, Complete and Verifiable Example。
A 'wallet file' 字面意思是类文件对象。它遵循与文件流对象相同的语义,Python 的 open()
是直接包装器。
只有 wallet_file
和 wallet_password
是特定于钱包文件的。 name
和 value
是您要传递给文件的键值对。
问题
您的问题在于能够测试您的写入是否 'clean'。
但是,您不需要检查文件是否已正确写入或是否已创建 -
您只会以这种方式测试 Python 的 file
对象,该对象已经过非常可靠的测试。
单元测试的目的是测试您编写的代码,而不是外部服务。应该总是假设外部服务在单元测试中完成了它的工作——你只在集成测试中测试外部服务。
您需要的方法是确保您发送的要写入的值被正确接收而不是乱码,并且您创建文件的请求是在你想要的格式。测试 消息 ,而不是 收件人 。
一种方法
一种技术是将您的输入抽象为 class,然后将其子class 以具有虚拟方法。然后,您可以将 subclass 用作美化的模拟,用于所有意图和目的。
换句话说,改变
def write_wallet_file_entry(name, value, wallet_file, wallet_password):
...
到
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)
为了测试,您现在可以创建 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
现在您可以在生产中使用相同的函数(只需传递 Wallet
!)和测试(只需传递 MockWallet
并检查该对象的属性!):
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)
瞧!您现在拥有一个经过测试的写入流程,其中包含一个方便的即兴模拟,仅使用 dependency injection 而不是任意函数参数。
我的代码看起来有点像这样:
def write_wallet_file_entry(name, value, wallet_file, wallet_password):
some_code
some_more_code_to_write_to_the_wallet
...
我正在使用 Python (2.6) 并使用 unittest 模块对此代码进行单元测试。代码创建钱包文件,如果它不存在然后写入一堆键值对。
一旦我写入钱包,就无法进行文本解析来确认写入是干净的。
澄清:说明不那么明显:我不能使用 "unittest.mock" 或 "mock" 模块,这会使问题更容易解决。我的环境卡在 python 2.6,没有 "virtualenv",没有 "mock" 模块,并且不允许在系统上安装外部模块。
任何建议都会很有帮助。
一些假设
这些假设不会改变我回答的要点,但它们意味着我们可以清楚地了解术语,因为您还没有发布 Minimum, Complete and Verifiable Example。
A 'wallet file' 字面意思是类文件对象。它遵循与文件流对象相同的语义,Python 的
open()
是直接包装器。只有
wallet_file
和wallet_password
是特定于钱包文件的。name
和value
是您要传递给文件的键值对。
问题
您的问题在于能够测试您的写入是否 'clean'。
但是,您不需要检查文件是否已正确写入或是否已创建 -
您只会以这种方式测试 Python 的 file
对象,该对象已经过非常可靠的测试。
单元测试的目的是测试您编写的代码,而不是外部服务。应该总是假设外部服务在单元测试中完成了它的工作——你只在集成测试中测试外部服务。
您需要的方法是确保您发送的要写入的值被正确接收而不是乱码,并且您创建文件的请求是在你想要的格式。测试 消息 ,而不是 收件人 。
一种方法
一种技术是将您的输入抽象为 class,然后将其子class 以具有虚拟方法。然后,您可以将 subclass 用作美化的模拟,用于所有意图和目的。
换句话说,改变
def write_wallet_file_entry(name, value, wallet_file, wallet_password):
...
到
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)
为了测试,您现在可以创建 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
现在您可以在生产中使用相同的函数(只需传递 Wallet
!)和测试(只需传递 MockWallet
并检查该对象的属性!):
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)
瞧!您现在拥有一个经过测试的写入流程,其中包含一个方便的即兴模拟,仅使用 dependency injection 而不是任意函数参数。