【问题标题】:Mocking with anonymous class in Java在 Java 中使用匿名类进行模拟
【发布时间】:2019-06-17 15:52:04
【问题描述】:

我正在学习依赖注入和使用 Mockito 进行测试。我刚刚找到了一个教程,其中有人解释了一个使用依赖注入和没有依赖注入的应用程序。这是链接:https://www.journaldev.com/2394/java-dependency-injection-design-pattern-example-tutorial

我有两个问题:

第一个问题是关于他为测试编写的代码。那是个什么样的嘲讽?你不需要使用@Mock 来模拟一个对象吗?

这是他的测试代码:

public class MyDIApplicationJUnitTest {

    private MessageServiceInjector injector;
    @Before
    public void setUp(){
        //mock the injector with anonymous class
        injector = new MessageServiceInjector() {

            @Override
            public Consumer getConsumer() {
                //mock the message service
                return new MyDIApplication(new MessageService() {

                    @Override
                    public void sendMessage(String msg, String rec) {
                        System.out.println("Mock Message Service implementation");

                    }
                });
            }
        };
    }

    @Test
    public void test() {
        Consumer consumer = injector.getConsumer();
        consumer.processMessages("Hi Pankaj", "pankaj@abc.com");
    }

    @After
    public void tear(){
        injector = null;
    }

} 

第二个问题是关于在没有依赖注入的情况下测试应用程序。我不明白他为什么这么说:“测试应用程序将非常困难,因为我们的应用程序直接创建电子邮件服务实例。我们无法在测试类中模拟这些对象。”为什么我们不能在测试用例中模拟这些对象。

【问题讨论】:

    标签: java junit dependency-injection mockito


    【解决方案1】:

    第一个问题是关于他为测试编写的代码。那是个什么样的嘲讽?你不需要使用@Mock 来模拟一个对象吗?

    要模拟一个对象,您必须提供一个具有相同类型的对象,即行为相同或者是您要模拟的对象的类的子类型。因此,要模拟一个对象,您可以使用匿名类的实例(在您的情况下,它将是扩展 MyDIApplication 的匿名类的对象),或者您可以使用 Mockito 及其 @Mock 注释,这基本上是类似的事情。基本上使用@Mock 注释与做类似:

    MyDIApplication myDiApplication = Mockito.mock(MyDIApplication.class)
    

    它创建了一个模拟对象扩展在构造函数中传递的类。在这里,您可以根据要模拟的内容传递接口或类。

    当使用匿名类时,你提供了你想在重写的方法实现中模拟的方法的实现,但在 Mockito 的情况下,你通过使用像 Mockito::when 这样的方法来提供意图行为。

    第二个问题是关于在没有依赖注入的情况下测试应用程序。我不明白他为什么这么说:“测试应用程序将非常困难,因为我们的应用程序直接创建电子邮件服务实例。我们无法在测试类中模拟这些对象。”为什么我们不能在测试用例中模拟这些对象。

    我猜你指的是这段代码:

    public class MyApplication {
    
        private EmailService email = new EmailService();
    
        public void processMessages(String msg, String rec){
            //do some msg validation, manipulation logic etc
            this.email.sendEmail(msg, rec);
        }
    }
    

    在这里,您创建一个 EmailService 的实例作为类字段。因此,您无法模拟它(尽管您可以使用反射或 PowerMock)。因此,您与EmailService 紧密耦合,并且很难测试MyApplication 类逻辑。为了能够对其进行测试,您可以使用构造函数注入:

    public class MyApplication {
    
        private EmailService email;
    
        public MyApplication(EmailService emaliService) {
           this.email = emailService;
        }
    
        public void processMessages(String msg, String rec){
            //do some msg validation, manipulation logic etc
            this.email.sendEmail(msg, rec);
        }
    }
    

    或者setter注入:

    public class MyApplication {
    
        private EmailService email;
    
        public void setEmailService(EmailService emailService) {
            this.email = emailService;
        }
    
        public void processMessages(String msg, String rec){
            //do some msg validation, manipulation logic etc
            this.email.sendEmail(msg, rec);
        }
    }
    

    【讨论】:

    • 我想补充一点,有几种不同类型的测试类:Dummy vs. Stub vs. Spy vs. Fake vs. Mock Mockito 可用于创建所有这些类型的对象,但它 (mockito) 并非完全必要。它(mockito)用于尝试和加快制作不同类型测试对象的过程。
    猜你喜欢
    • 2021-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多