Java 在JUnit测试中使用常量或字段

Java 在JUnit测试中使用常量或字段,java,junit,Java,Junit,在编写单元测试时,我一直遇到同一个问题。考虑下面的类: class Dog { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() {

在编写单元测试时,我一直遇到同一个问题。考虑下面的类:

class Dog {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

public class MyTest {

    private static final Dog DOG = createDog();
    private static final String DOG_NAME = "rex";
    private static final int DOG_AGE = 3;

    private static Dog createDog() {
        Dog dog = new Dog();
        dog.setName(DOG_NAME);
        dog.setAge(DOG_AGE);
        return dog;
    }

    @Test
    public void testName() throws Exception {
        SomeObject outcome = classUnderTest.doSomething(DOG);

        assertThat(outcome.getName(), is(DOG_NAME));
        assertThat(outcome.getAge(), is(DOG_AGE));
    }

}

public class MyTest2 {

    private static final String DOG_NAME = "rex";
    private static final int DOG_AGE = 3;

    private Dog dog;

    @Before
    public void setUp() {
        dog = createDog();
    }

    @Test
    public void testName() throws Exception {
        SomeObject outcome = classUnderTest.doSomething(DOG);

        assertThat(outcome.getName(), is(DOG_NAME));
        assertThat(outcome.getAge(), is(DOG_AGE));
    }

    private Dog createDog() {
        Dog dog = new Dog();
        dog.setName(DOG_NAME);
        dog.setAge(DOG_AGE);
        return dog;
    }

}

把狗当作一个恒量还是作为一块田来抓比较好?如果这个问题只是基于意见,我将关闭它。

这是运行测试时的常见模式。。。你需要数据!有几个选择

  • 复制粘贴(如您所示)
  • 模式
  • 或者是甜美的图案
测试数据构建器模式的思想是,您只需引用与测试相关的明确信息

因为您使用的是Java,所以有一个称为的小框架可以简化这些构建器的创建。。。还有一个intellij插件,它可以自动生成构建器,使用它可以使它变得简单,因此只需一个快捷方式,您就可以完成所有设置


现在,回答您的问题:这种模式的结果是,在测试中很少需要数据作为常量。您希望使测试尽可能明确,而不是添加间接层。。。因此,答案既不是常数也不是字段,而是测试本身的局部变量。

如果你的狗是可变的(它有设置器),它就不是常数。我更愿意将其设置为局部变量,因为将其作为成员变量(静态或其他)意味着您可能会意外地将状态挂起,而您并不打算使用它。嗯,每次测试之前都会调用setUp方法get,所以我不能在这种状态下运行。@AndyTurner普遍同意。但是JUnit在每个测试方法之前创建测试类的新实例,并在每个测试方法之前调用setUp()方法。因此,状态,即使存储为字段,也只能通过单个测试方法使用。这是创建通用测试夹具的经典方法。使用静态可变状态是错误的,因为测试的顺序可能会改变结果:测试不再是独立的。是的,但我将其设置为静态最终字段@JBNizet如果它是最终的,他们怎么能改变它呢?如果你得到的不仅仅是一个测试,需要同一只狗呢。你会在每个测试中创建/构建这只狗作为局部变量吗?@Chris311是的,这就是想法。我假设每个测试都需要一个稍微不同的Dog实例,因此您可以在测试中定制实例。如果我查看您发布的代码,使用此模式将添加一个类(构建器)并删除测试类中的所有内容,除了用
@test
注释的实际方法。好的,考虑以下情况:您想喂狗。所以你模仿了一个叫做feeder.feed(狗,食物)的方法。你想用同样的食物喂不同的狗。所以食物永远不会改变。假设会有一个FoodBuilder。你如何定义食物?还是每个测试的局部变量?@Chris311我想在这种情况下,我会在每个测试中实例化狗(因为它们不同),对于食物,我可能会将其设置为测试的属性,但我并不完全喜欢这个想法(因为它引入了一层间接性,这意味着测试更难理解)。如果这感觉很难做到,它可能是指向一个设计问题。。。只要提到测试有助于发现设计问题就好了:)。有时候,间接层并不是一件坏事。有时,如果哪种狗粮无关紧要,你只需给一种恒定的狗粮命名即可。