【问题标题】:What is the correct way to unit test a function or method that writes to an encrypted wallet file?对写入加密钱包文件的函数或方法进行单元测试的正确方法是什么?
【发布时间】:2017-06-07 07:22:15
【问题描述】:

我的代码看起来有点像这样:

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”模块,并且不允许在系统上安装外部模块。

任何建议都会很有帮助。

【问题讨论】:

  • 您不需要外部库来编写自己的模拟对象。只需将wallet_filewallet_password 抽象为Wallet 类,将函数签名更改为接受Wallet 类,然后传入一个专门用于测试的子类。
  • @AkshatMahajan - 你能举个例子吗?此外,请将您的评论升级为答案,如果您提供示例,我会接受。
  • 当然。由于我对您的代码的工作原理一无所知,因此我假设 namevalue 是您要写入钱包文件的键值对。

标签: python unit-testing wallet


【解决方案1】:

一些假设

这些假设不会改变我回答的主旨,但它们意味着我们可以清楚术语,因为您尚未发布 Minimum, Complete and Verifiable Example

  • “钱包文件”实际上是一个类似文件的对象。它遵循与文件流对象相同的语义,Python 的open() 是其直接包装器。

  • 只有 wallet_filewallet_password 是特定于钱包文件的。 namevalue 是您希望传递给文件的键值对。

问题

您的问题在于能够测试您的写入是否“干净”。

但是,您不需要检查文件是否正确写入或是否已创建 - 你只会以这种方式测试 Python 的 file 对象,它已经经过了非常强大的测试。

单元测试的重点是测试您编写的代码,而不是外部服务。应该总是假设外部服务在单元测试中完成了它的工作——你只在集成测试中测试外部服务。

需要的是一种方法,以确保您发送的要写入的值被正确接收且没有乱码,并且您创建文件的请求以您想要的格式接收。测试消息,而不是收件人

一种方法

一种技术是将您的输入抽象为一个类,并将其子类化为具有虚拟方法。然后,您可以将子类用作美化的模拟,用于所有意图和目的。

换句话说,改变

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 而不是任意函数参数。

【讨论】:

    猜你喜欢
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 2019-11-08
    • 2014-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多