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

Java 在单元测试中检查工厂的结果,java,unit-testing,tdd,Java,Unit Testing,Tdd,我开发了一些行为类似的类,它们都实现了相同的接口。我实现了一个工厂,它创建适当的对象并返回接口。我正在为工厂编写单元测试。返回的只是对象的接口。 测试工厂是否正常工作的最佳方法是什么 我想知道Java的答案,但是如果有一个跨语言的解决方案,我想知道 2号。在答案中,会像另一个答案那样做吗?如果是这样的话,我会将另一个答案也标记为已接受,并改写我的问题,以处理返回接口的工厂,您不知道实现接口的具体类的类型,以及您确实知道使用了什么具体类的情况。因为我不知道您的工厂方法是什么样子,我现在唯一能建议的

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

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


2号。在答案中,会像另一个答案那样做吗?如果是这样的话,我会将另一个答案也标记为已接受,并改写我的问题,以处理返回接口的工厂,您不知道实现接口的具体类的类型,以及您确实知道使用了什么具体类的情况。

因为我不知道您的工厂方法是什么样子,我现在唯一能建议的就是

  • 检查对象是否是您所寻找的正确的具体实现:

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

  • 更新:

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

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

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

    IMyInterface fromFactory = factory.create(...);  
    Assert.assertEquals(fromFactory.getClass().getName(), MyInterfaceImpl1.class.getName());
    
    如果您认为这可能会以某种方式失败(我无法想象),请进行两次验证。

    您尝试的不是单元测试 如果测试返回的对象是否是特定具体类的实例,那么就不是单元测试。您正在进行集成测试。虽然集成测试很重要,但它不是一回事

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

    一般来说,对象的单元测试 在进行单元测试时,您需要声明四件事:

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

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

    由于工厂不会随着时间的推移而改变(因为那时他们将是“构建者”,这是另一种模式),因此没有需要测试的命令

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

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

    单元测试工厂概述
  • 不要测试返回对象的行为或实现细节!您的工厂不负责对象实例的实现
  • 测试是否收到发送到依赖项的命令
  • 就这样。如果没有依赖项,就没有要测试的内容。除了可能声明返回的对象不是
    null
    引用之外

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


    这里的其他人已经回答了如何使用
    instanceof
    操作符执行此操作。

    如果您的工厂返回一个具体实例,您可以使用@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());
        }
    }
    
    package it.sorintlab.pxrm.proposition.model.factory.task;
    导入org.junit.Test;
    导入java.util.array;
    导入java.util.Collection;
    导入org.junit.runner.RunWith;
    导入org.junit.runners.Parameterized;
    导入org.junit.runners.Parameterized.Parameters;
    导入静态org.junit.Assert.*;
    @RunWith(参数化的.class)
    公共类TaskFactoryTest{
    @参数
    公共静态收集数据(){
    返回Arrays.asList(新对象[][]{
    {“sas:wp | repe”,WorkPackageAvailabilityFactory.class},
    {“sas:wp | people”,WorkPackagePeopleFactory.class},
    {“edu:wp | course”,WorkPackageCourseFactory.class},
    {“edu:wp | module”,WorkPackageModuleFactory.class},
    {“else”,AttachmentTaskDetailFactory.class}
    });
    }
    私有字符串fInput;
    
    private ClassI同意,但我不认为检查类名的相等性是多余的。只检查类应该足够好。为什么要测试类中的方法返回相等的值,而不是直接比较类对象?此外,Sandi Metz关于单元测试的精彩演讲:如何进行单元测试对于工厂本身构造的对象,“接收发送到其他对象的命令”
    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());
        }
    }