有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在实现void方法之前测试它?

我正在开发一个新项目。这就是迄今为止所做的:

  1. 技术设计
  2. 模型类(数据类)
  3. 项目中的所有接口(但尚未实现)

接下来我要做的是实现从骨架(高级方法)到嵌套对象的方法。然而,在编写实现之前,我想为每个方法创建一个单元测试。首先实现高级方法不会有任何问题,因为我将使用接口并仅在使用DI的外部Java配置文件中绑定具体实现

我要实现的第一个方法是lookForChanges(),它接受并返回void。Spring的调度器(@Scheduled)调用这个方法,并管理整个过程:它从数据库检索数据,从web服务检索数据,比较它们,如果有任何更改,则更新数据库并向客户端发送JMS消息。当然,它本身并不做所有这些事情,但它调用了相关的类和方法

所以我遇到的第一个问题是如何创建一个void方法的单元测试。在所有教程中,测试的方法都会接受参数并返回结果。我已经找到了答案。他说,即使没有结果需要检查,至少有人可以确保被测试方法中的方法被调用,并且参数顺序正确

我有点喜欢这个答案,但问题是,我在使用TDD,所以与问这个问题的人相反,我在实现测试方法之前编写测试,所以我还不知道它将使用哪些方法以及以什么顺序使用。我可以猜,但我只能确定,一旦这个方法已经实现了

那么,在实现一个void骨架方法之前,我该如何测试它呢


共 (1) 个答案

  1. # 1 楼答案

    So the first problem I'd had is how to create a unit test to a void method.

    void方法意味着合作者。你要核实一下

    例如。假设我们需要一个将System.in复制到System.out的任务。我们将如何为此编写一个自动化测试

    void copy() {
        // Does something clever with System.in and System.out
    }
    

    但如果你稍微眯一眼,你会发现你的代码看起来像

    void copy() {
        InputStream in = System.in;
        PrintStream out = System.out;
        // Does something clever with `in` and `out`
    }
    

    如果我们在此基础上执行并提取方法重构,那么我们可能会得到如下代码

    void copy() {
        InputStream in = System.in;
        PrintStream out = System.out;
        copy(in, out);
    }
    
    void copy(InputStream in, PrintStream out) {
        // Does something clever with `in` and `out`
    }
    

    后者是一个我们可以测试的API——我们配置协作者,将它们传递给被测系统,然后验证更改

    目前,我们没有对void copy()进行测试,但这没关系,因为那里的代码“非常简单,显然没有缺陷”

    请注意,从测试的角度来看,以下设计之间没有太大区别

    {
        Task task = new Task();
        task.copy(in, out);
    }
    
    {
        Task task = new Task(in, out);
        task.copy();
    }
    
    {
        Task task = Task.createTask();
        task.copy(in, out)
    }
    
    {
        Task task = Task.createTask(in, out);
        task.copy();
    }
    

    对此的一种思考方式是:我们不是先编写API,而是先编写测试

    // Arrange the test context to be in the correct initial state
    // ???
    // Verify that the test context arrived in final state consistent with the specification.
    

    也就是说,在开始考虑API之前,首先需要弄清楚如何评估结果

    相同的想法,不同的拼写:如果函数调用的效果不可检测,那么你最好只发送一个no-op。如果no-op不符合你的要求,那么在某个地方一定有一个可观察的效果,你只需要确定该效果是否被直接观察到(检查返回值),或者通过代理(检查对解决方案中其他一些元素的影响,或者扮演该元素角色的双重测试)

    OK so now I can pass params to the method for testing it, but what can I test?

    你测试它应该做什么

    试试这个思维实验——假设你和我配对,你提出了这个界面

    interface Task {
        void lookForChanges();
    }
    

    然后,经过深思熟虑,我实现了这一点:

    class NoOpTask implements Task {
        @Override
        void lookForChanges() {}
    }
    

    您如何证明我的实现不满足要求

    您在该问题中所写的是“它更新数据库并向客户机发送一个JMS消息”,因此有两个断言要考虑——数据库是否被更新,并且是一个JMS消息发送?

    整件事看起来像这样

    Given:
        A database with data `A`
        A webservice with data `B`
        A JMS client with no messages
    
    When:
        The task is connected to this database, webservice, and JMS client
        and the task is run
    
    Then:
        The database is updated with data `B`
        The JMS client has a message.
    

    It looks like what you suggest is an end-to-end test.

    看起来确实像。但是,如果您对这些合作者使用双重测试,而不是实时系统,那么您的测试是在一个孤立的、确定性的shell中运行的

    这可能是一个社交测试——测试不知道或不关心when子句中被测试系统的实现细节。我不认为SUT是一个“单元”

    I have to see the implementation of foo first. Am I wrong?

    是的-您需要了解foo的规范,而不是实现