Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/wordpress/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在实现void方法之前对其进行测试?_Java_Unit Testing_Oop_Design Patterns_Tdd - Fatal编程技术网

Java 如何在实现void方法之前对其进行测试?

Java 如何在实现void方法之前对其进行测试?,java,unit-testing,oop,design-patterns,tdd,Java,Unit Testing,Oop,Design Patterns,Tdd,我正在开发一个新项目。这是迄今为止所做的: 技术设计 模型类(数据类) 项目中的所有接口(但尚未实现) 接下来我要做的是实现从骨架(高级方法)到嵌套对象的方法。然而,在编写实现之前,我想为每个方法创建一个单元测试。首先实现高级方法不会有任何问题,因为我将使用接口并仅在使用DI的外部Java配置文件中绑定具体实现 我要实现的第一个方法叫做lookForChanges(),它接受并返回void。此方法由Spring的调度器(@Scheduled)调用,它管理整个过程:从DB检索数据,从web服务检索

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

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

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

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

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

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

    所以我遇到的第一个问题是如何为void方法创建一个单元测试

    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`
    }
    
    如果我们在此基础上执行并提取方法重构,那么我们可能会得到如下代码

    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,而是先编写测试

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

    相同的想法,不同的拼写:如果函数调用的效果不可检测,那么您也可以发送一个no-op。如果no-op不符合您的要求,那么一定有一个可观察的效果——您只需要确定该效果是直接观察到的(检查返回值),还是通过代理观察到的(检查对溶液中某些其他元素的影响,或扮演该元素角色的双重测试)

    好的,现在我可以把参数传递给测试它的方法,但是我可以测试什么呢

    你测试它应该做什么

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

    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.
    
    看起来你建议的是端到端测试

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

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

    我必须先看看foo的实现,我错了吗


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

    该方法应该做什么?这决定了您应该测试什么。无效方法更难测试,因为您需要在测试代码中观察副作用,这被认为是一种反模式。那么,什么是
    lookForChanges()
    应该在被测类的状态下修改吗?@MickMnemonic我已经解释了它应该做什么:交互DB层以检索数据,交互Web服务层以检索数据,比较两个位置的数据,如果它们之间存在差异,则它交互DB层以更新DB,以及交互它是JMS层,用于向客户端发送通知。它不会更改对象状态(名为MainService)中的任何内容。这很公平。该方法基本上等同于
    main()
    ,为其编写单元测试当然是可能的,但不会增加太多价值,因为您主要是针对mock测试交互(DB、WS、JMS)。也许可以将数据比较提取到一个单独的、单元可测试的方法/类中?@MickMnemonic是的,当然,这个方法本身不会进行比较,但会调用另一个方法来进行比较