如何对没有逻辑的类进行单元测试?

3

我发现编写算法单元测试很容易。例如,对于sort(List)这个方法,我们可以很容易地编写如下的测试:

list = [2, 1, 4];
assert(sort(list) == [1, 2, 4]);

但我发现很难测试没有逻辑,没有if语句,只有一系列调用的方法。

主要有两个例子,我希望能得到如何对它们进行单元测试的答案:

例子1:

假设我有一个负责将数据写入文件的类,但是该数据以特定方式由外部函数(writeHeaderToFilewriteSerializedDatawriteEndOfFile)写入。

数据不是直接按原样写入文件的,所以如果数据像这样:

{
    list: [
        "item 1",
        "item 2"
    ],
    name: "aaa"
}

这并不意味着该文件既不是该数据的纯文本版本(没有空格),也不会是简单的序列化或加密版本。实际的文件二进制将是我无法知晓的内容。我只知道可以使用这3种方法来正确写入。
此文件还包含一些其他信息,这些信息不直接来自这3种方法,例如特定类型的标头(我也不知道它在文件二进制中如何表示)。
这就是该类:
class FileCreator {
    populateFileWithData(File file, Data data) {
        doBlockWithLock(file, {
            Header header;
            header.format = SomeFormat;
            header.version = SomeVersion;
            writeHeaderToFile(file, header);

            writeSerializedData(file, data);

            writeEndOfFile(file);
        });
    }

    // Private
    void doBlockWithLock(File file, Lambda block) {
        file.holdWritingLock();
        block();
        file.releaseWritingLock();
    }
}

示例2:

class Controller {

    var screenOne = new ScreenOne();
    var screenTwo = new ScreenTwo();
    var screenThree = new ScreenThree();

    void reloadButtonWasClicked() {
        screenOne.reload();
        screenTwo.reload();
        screenThree.reload();
    }
}

对于这个问题,我可以做出以下解释:

var mockScreenOne = Mock<ScreenOne>().reload.expectOneCall();
var mockScreenTwo = Mock<ScreenTwo>().reload.expectOneCall();
var mockScreenThree = Mock<ScreenThree>().reload.expectOneCall();

Controller controller = new Controller();
controller.screenOne = mockScreenOne;
controller.screenTwo = mockScreenTwo;
controller.screenThree = mockScreenThree;

controller.reloadButtonWasClicked();

mockScreenOne.verify();
mockScreenTwo.verify();
mockScreenThree.verify();

但我认为这并没有太多价值,因为我只是断言我正在实现相同的事情。对我来说看起来像是重复代码。


测试我的两个示例的正确方法是什么?


如果我在测试它,我会简单地测试FileCreator.populateFileWithData是否完成而不抛出异常。我还会检查目标文件是否存在(因为它应该存在),然后再删除我的临时测试文件。对于第二个测试,我会检查每个屏幕是否对重新加载做出了适当的反应;它是否填写了应该填写的内容而没有错误。 - Ian Boyd
@RodrigoRuiz 在这种情况下更有价值的可能是集成测试而不是单元测试。文件创建者与序列化器的实现是否会生成正确的文件?点击重新加载按钮是否会在视图中产生正确的行为?然而,由于类的简单性,它们可能不需要经过测试。它们非常简单,要么工作正常,要么不工作。您可能会通过简单地使用应用程序注意到错误的存在。 - thalesmello
@thalesmello,关于FileCreator,只有集成测试而没有单元测试怎么办? - Rodrigo Ruiz
@RodrigoRuiz 我没有完全理解这个例子。writeHeaderToFile、writeSerializedData和writeEndOfFile是根据输入类型以不同方式调用的吗?还是无论输入如何,它们总是相同的?在第一种情况下涉及到逻辑,而在第二种情况下似乎没有任何逻辑。 - thalesmello
@RodrigoRuiz 看起来这个类没有逻辑。所以我不会测试它。 - thalesmello
显示剩余5条评论
1个回答

1
在第一个例子中,如果您编写了相关的消息并且对测试覆盖率感到满意,则无需在FileCreator上复制该测试逻辑。 您只需要测试FileCreator populateFileWithData方法以确保文件已写入,以及锁定机制是否正常工作即可。
您是正确的,您最后的测试相当琐碎。我会倾向于省略它。但这取决于情况。有可能有人会来注释掉其中一个面板构造函数吗?您是否有其他测试可以识别这样的问题?

它们之间的相似之处在于它们都没有逻辑。 1)假设这3个方法已经被测试过且不是我的。如果我无法访问反序列化函数,我该如何测试它?另外,假设我正在创建反序列化函数,那么它是一个单独的逻辑,我不想在填充文件数据方法的单元测试中复制它。2)您所说的省略是指不测试它吗? - Rodrigo Ruiz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接