简体   繁体   English

对写入加密的钱包文件的函数或方法进行单元测试的正确方法是什么?

[英]What is the correct way to unit test a function or method that writes to an encrypted wallet file?

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. 我正在使用Python(2.6)并使用unittest模块对该代码进行单元测试。 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. 澄清:说的不是那么明显:我不能使用“ unittest.mock”或“ mock”模块,这会使问题更容易解决。 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. 我的环境停留在python 2.6上,没有“ virtualenv”,没有“ mock”模块,并且不允许在系统上安装外部模块。

Any suggestions would be really helpful. 任何建议都会很有帮助。

Some Assumptions 一些假设

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. 它遵循与文件流对象相同的语义,对此,Python的open()是直接包装器。

  • Only the wallet_file and wallet_password are wallet file-specific. 只有wallet_filewallet_password是特定于钱包文件的。 name and value are a key-value pair you seek to pass in to the file. namevalue是您想要传递给文件的键值对。

The Issue 问题

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. 但是,你并不需要检查,如果文件被正确写入,或者如果它被创造-你只可以测试Python的file反对这种方式,这是非常强劲已经测试。

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 . 测试邮件 ,而不是收件人

An Approach 一种方法

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 : 为了进行测试,您现在可以创建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!): 现在,您可以在生产环境中使用相同的功能(只需通过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)

Voila! 瞧! You now have a tested write flow with a handily-improvised mock using nothing more than dependency injection instead of arbitrary function parameters. 现在,您已经有了一个经过测试的编写流程,该流程具有一个手动改进的模拟程序,仅使用依赖项注入而不是任意函数参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM