我如何对无效功能进行单元测试?

时间:2014-01-19 17:16:26

标签: java unit-testing junit

class Elephant extends Animal {   
    public Elephant(String name) {
        super(name);
    }

    void makeNoise() {
        logger.info(" Elephant  make Sound");
    }

    void perform(String day) {
        if (day.equals("thursday") || day.equals("friday")) {
            makeNoise();
        }
    }
}

现在我要测试perform方法。如何使用JUnit对此方法进行单元测试?

4 个答案:

答案 0 :(得分:3)

Mockito Spy的解决方案

import org.junit.Test;

import static org.mockito.Mockito.*;

public class ElephantTest {

    @Test
    public void shouldMakeNoise() throws Exception {

        //given
        Elephant elephant = spy(new Elephant("foo"));

        //when
        elephant.perform("friday");

        //then
        verify(elephant).makeNoise();

    }
}

否定测试:

@Test
public void elephantShouldDontMakeNoisesOnMonday() {

    //given
    Elephant elephant = spy(new Elephant("foo"));

    //when
    elephant.perform("monday");

    //then
    verify(elephant, never()).makeNoise();

}

@Test
public void shouldDoNotMakeNoisesOnMonday() {

    //given
    Elephant elephant = spy(new Elephant("foo"));

    //when
    elephant.perform("monday");

    then(elephant).should(never()).makeNoise();

}

依赖

org.mockito:mockito-core:2.21.0

了解

答案 1 :(得分:2)

void()函数可以更改程序的状态。这可以通过修改变量,文件,数据库等来完成。

在你的情况下,你正在写一个记录器。如果这导致将“Elephant make Sound”写入文件,那么您可以读取该文件并查看文件中的数据是否包含嘈杂的大象。

但是,如果它不涉及任何你可以检查的东西(即:它只是在控制台上显示输出)那么你可能想要查看某种形式的依赖注入(DI),你可以在其中设置输出到文件或其他你可以轻松阅读的东西。

应该注意的是,您可以通过模拟对象并检查相应的方法被调用来绕过DI。

答案 2 :(得分:0)

要测试任何方法,必须通过更改任何变量的状态从方法的外部看到要测试的责任。

通常通过从方法返回值来完成。但是如果没有它,可以通过从方法范围之外修改某些东西来完成它,以防你有任何“问题”从方法中返回一些内容!

在您的情况下,您只记录一些消息。并且您的代码在某种意义上并不是真正可测试的,因为它不会执行与更改任何变量的状态直接相关的内容(因为您更改了除变量之外的其他资源的状态,这是您的代码无法直接访问的。必须编写一些代码来从外部资源中读取更改,因此也会使您的测试代码依赖于读取。如果您在阅读时遇到一些问题,那么您的测试用例将无法通过,并且不符合该单元的精神测试。主要思想是尽可能减少对外部代码或库的依赖。但是你的代码可以通过执行轻微的重构/转移责任来测试,如下所示:

String makeNoise() {
    return "Elephant  make Sound";
}

String perform(String day) {
    if (day.equals("thursday") || day.equals("friday")) {
      return makeNoise();
    }
}

然后你将记录从perform方法返回的值的记录转移到使用它的方法,如下所示:

 logger.info(perform(day));

答案 3 :(得分:0)

根据您愿意使用的工具和测试的深度,您有多种选择。

使用普通Java进行部分模拟

创建一个从大象扩展的类(MockElephant),覆盖makeNoise,以便计算调用次数。在测试中使用该类来检查makeNoise被称为正确的次数

使用框架进行部分模拟 您基本上和上面一样,但不是手动编码MockElephant,而是使用一些模拟框架创建它。使测试更简单,因为您需要更少的代码。它更容易阅读。但如果发生奇怪的事情,就会更难理解发生了什么。在Mocking框架的情况下,我认为它们是值得的。

这称为Partial Mocking的原因是你只模拟一个类的一部分(在这种情况下是一个方法)。

另一种方法是使用普通模拟,这在您的情况下似乎是可行的(但在遗留代码中可能变得很难)。

在这里,您将注入Logger作为依赖项。例如,您可以创建一个允许您提供Logger的附加构造函数。在您的测试中,您将使用模拟的Logger,它再次计算它的调用,可能与它收到的参数一起并检查它是否具有预期的值。

再次,您可以使用Mocking Framework或使用普通的旧Java来实现这一目标。