在单元测试中检查工厂的结果

时间:2008-09-01 00:40:04

标签: java unit-testing tdd

我开发了一些具有类似行为的类,它们都实现了相同的接口。我实现了一个工厂,它创建适当的对象并返回接口。我正在为工厂写一个单元测试。你得到的只是对象的接口。 测试工厂工作正常的最佳方法是什么?

我想知道Java中的答案,但如果有一个跨越语言的解决方案,我想知道它。

答案中的第2号,会像其他答案那样完成吗?如果是这样,我将标记另一个接受的答案并重新提出我的问题,以解决返回界面的工厂以及您不知道哪种类型的具体类实现了界面,以及您知道具体类是什么的情况使用

5 个答案:

答案 0 :(得分:25)

您要做的不是单元测试

如果您测试返回的对象是否是特定具体类的实例,则不是单元测试。你是集成测试。虽然集成测试很重要,但它不是一回事。

在单元测试中,您只需要测试对象本身。如果断言返回的抽象对象的具体类型,那么您正在测试返回对象的实现。

一般对象的单元测试

当进行单元测试时,有四件事你想断言:

  1. 查询的返回值(非空方法)是您所期望的。
  2. 命令的副作用(void方法)按照您的预期修改对象本身。
  3. 收到发送给其他对象的命令(通常使用模拟完成)。
  4. 此外,您只想测试从对象实例(即公共接口)可以观察到的内容。否则,您将自己绑定到一组特定的实现细节。这将要求您在这些细节发生变化时更改测试。

    单元测试工厂

    对工厂的单元测试真的无趣,因为您对返回的查询对象的行为不感兴趣。这种行为(希望)可以在其他地方进行测试,也可以在对象本身进行单元测试时进行测试。您只对返回的对象是否具有正确的类型感兴趣,如果您的程序编译,则可以保证。

    由于工厂不随时间而变化(因为那时它们将是“建筑商”,这是另一种模式),因此没有可测试的命令。

    工厂负责实例化对象,因此他们不应该依赖其他工厂为他们做这件事。他们可能依赖于Builder,但即便如此,我们也不应该测试Builder的正确性,只测试Builder是否收到消息。

    这意味着您必须在Factories上测试的是他们是否将消息发送到他们所依赖的对象。如果使用依赖注入,这几乎是微不足道的。只需在单元测试中模拟依赖项,并验证它们是否收到了消息。

    单元测试工厂总结

    1. 不要测试返回对象的行为和实现细节!您的工厂不负责实施对象实例!
    2. 测试是否收到发送给依赖项的命令。
    3. 就是这样。如果没有依赖关系,则无需测试。除了可能断言返回的对象不是null引用。

      集成测试工厂

      如果您要求返回的抽象对象类型是特定具体类型的实例,那么这属于集成测试。

      其他人已经使用instanceof运算符解答了如何执行此操作。

答案 1 :(得分:18)

由于我不知道您的工厂方法如何,我现在可以建议的是

  1. 检查对象是否是您正在寻找的正确具体实现:

    IMyInterface fromFactory = factory.create(...);  
    Assert.assertTrue(fromFactory instanceof MyInterfaceImpl1);
    
  2. 您可以检查工厂是否使用有效的实例变量设置具体实例。

答案 2 :(得分:0)

if (myNewObject instanceof CorrectClass)
{
    /* pass test */
}

<强>更新

不知道为什么这会被标记下来,所以我会稍微扩展一下......

public void doTest()
{
    MyInterface inst = MyFactory.createAppropriateObject();
    if (! inst instanceof ExpectedConcreteClass)
    {
        /* FAIL */
    }
}

答案 3 :(得分:0)

@ cem-catikkas我认为比较getClass()。getName()值会更正确。在MyInterfaceImpl1类是子类的情况下,您的测试可能会被破坏,因为子类是MyInterfaceImpl1的实例。我会改写如下:

IMyInterface fromFactory = factory.create(...);  
Assert.assertEquals(fromFactory.getClass().getName(), MyInterfaceImpl1.class.getName());

如果您认为这可能会以某种方式失败(我无法想象),请进行两次验证。

答案 4 :(得分:0)

如果您的工厂返回了具体实例,则可以使用 @Parameters 批注以获得更灵活的自动单元测试。

package it.sorintlab.pxrm.proposition.model.factory.task;

import org.junit.Test;

import java.util.Arrays;
import java.util.Collection;

import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import static org.junit.Assert.*;

@RunWith(Parameterized.class)
public class TaskFactoryTest {

    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {
                { "sas:wp|repe" , WorkPackageAvailabilityFactory.class},
                { "sas:wp|people", WorkPackagePeopleFactory.class},
                { "edu:wp|course", WorkPackageCourseFactory.class},
                { "edu:wp|module", WorkPackageModuleFactory.class},
                { "else", AttachmentTaskDetailFactory.class}
        });
    }

    private String fInput;
    private Class<? extends TaskFactory> fExpected;

    public TaskFactoryTest(String input, Class<? extends TaskFactory> expected) {
        this.fInput = input;
        this.fExpected = expected;
    }

    @Test
    public void getFactory() {
        assertEquals(fExpected, TaskFactory.getFactory(fInput).getClass());
    }
}

此示例是使用 Junit4 创建的。您会注意到,仅用一行代码就可以测试Factory方法的所有结果。