打破局部依赖关系以对void方法进行单元测试 [英] Breaking a local dependency to unit test a void method

查看:129
本文介绍了打破局部依赖关系以对void方法进行单元测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Mockito进行练习,但是对于如何测试依赖于本地对象中对方法的调用的方法,我有些犹豫. 请参见以下示例:

I am practicing with mockito, but I am a bit stuck on how to test a method that depends on a call to method in a local object. See the following example:

public class Worker {          

    public void work() {
                   Vodka vodka = new Vodka();
                   vodka.drink();
     }
}

这个工人,而不是干活,他喜欢喝酒.但是我想添加一个测试来证明他在工作时喝酒.但是没有办法,因为我必须在调用方法work时验证是否调用了drink()方法.我认为您同意我的观点,这是无法测试的,因此在开始测试之前,我需要打破依赖关系. 这是我的第一个疑问,您认为打破这种依赖性的最佳方法是什么? 如果我只是将伏特加对象的范围更改为global,我认为那是不好的(我不想将其暴露给类的其他部分).我考虑过要创建工厂,像这样:

This worker, instead of doing his job, he likes drinking. But I want to add a test to prove that he drinks while he works. But there is no way of doing so, because I must verify that the method drink() is called when the method work is called. I think you agree with me, that this is impossible to test, so I need to break the dependency before starting to test. Here is my first doubt, what do you think is the best way of breaking such dependency? If I just change the scope of the vodka object to global, I think would not be good(I don't want to expose it to other parts of the class). I thought about creating a factory, something like this:

public class Worker {          

    private VodkaFactory vodkaFactory = new VodkaFactory();


    public void work() {
                   Vodka vodka = vodkaFactory.getVodka();
                   vodka.drink();
     }
}

我不确定我是否正确打破了依赖关系,但是我现在想做的是测试执行work()时是否调用了Drink()方法. 我没有运气尝试过这个

I am not sure if I did break the dependency correctly, but what I want to do now, is test that the method drink() is called when work() is executed. I tried this with no luck:

@Test
    public void
    does_the_worker_drink_while_working
    () {
        VodkaFactory vodkaFactory = mock(VodkaFactory.class);
        Vodka vodka = mock(Vodka.class);
        Worker worker = new Worker();
        worker.work();
        when(vodkaFactory.getVodka()).thenReturn(vodka);
        verify(vodka,times(1)).drink();
    }

我模拟了工厂,何时将检测到工厂创建了新的伏特加对象.但是,当我想验证该方法调用了Drink()方法的1倍时,mockito告诉我:

I mock the factory and the when will detect that a new Vodka object is created by the factory. But then when I wan to verify that that method calls 1 time the method drink(), mockito tells me:

Wanted but not invoked:
vodka.drink();
-> at testing_void_methods_from_local_objects.WorkerSpecification.does_the_worker_drink_while_working(WorkerSpecification.java:22)
Actually, there were zero interactions with this mock.

我没有正确进行存根或做错了什么.您能否帮我完成此测试,并向我说明测试这种无法验证的方法的最佳方法是什么?

I am not stubbing correctly or I am doing something wrong. Could you give me a hand completing this test and also clarify me what would be the best way of testing such untesteable methods?

我知道mockito有一个名为doAnswer()的方法,该方法用于模拟方法调用,您认为这种方法在这种情况下有用吗? 我应该如何使用它?

I know mockito has a method called, doAnswer() which is used to mock a method call,do you think it can be useful in this case? How should I use it?

更新:

我正在遵循在work()之前调用when()的建议,并且我试图允许从类之外设置工厂:

I am following the suggestions to get the when() called before the work() and also I am trying to allow the factory to be set from outside of the class:

@Test
public void
does_the_worker_drink_while_working
() {
    VodkaFactory vodkaFactory = mock(VodkaFactory.class);
    Vodka vodka = mock(Vodka.class);
    Worker worker = new Worker();
    when(vodkaFactory.getVodka()).thenReturn(vodka);
    worker.work();
    verify(vodka,times(1)).drink();
}

现在这是生产代码:

public class Worker {          


        private VodkaFactory vodkaFactory;

        public void work() {
                       Vodka vodka = vodkaFactory.getVodka();
                       vodka.drink();
         }

         public void setVodkaFactory(VodkaFactory vodkaFactory) {
               this.vodkaFactory = vodkaFactory;
         }

我得到的异常如下:

 java.lang.NullPointerException
        at testing_void_methods_called_from_local_objects.Worker.work(Worker.java:9)

这是显示vodka.drink()

对不起,我仍然对问题出在什么地方感到困惑.

Sorry by I still confused on what is the problem.

推荐答案

您的工人在这里创建自己的工厂类:

Your worker creates his own factory class here:

private VodkaFactory vodkaFactory = new VodkaFactory();

您正在创建的模拟与工作实例完全分离,因此缺乏交互性.为了使其正常运行,必须通过"构造函数注入.

The mock you are creating is completely detached from the worker instance and thus the lack of interaction. To make it work, factory has to be injected to worker from "the outside", say via constructor injection.

如果这是旧代码,则可以使用反射将模拟的私有工厂实例替换为私有工厂实例.

If this is legacy code, you could use reflection to replace private factory instance with mocked one.

正如JB Nizet在评论中指出的那样,您的模拟设置是在已经调用work之后进行的.为了正确处理,请在调用任何使用它的代码之前,先对其进行注入并进行设置.

As noted by JB Nizet in comment, your mock setup comes after work is already called. In order to make things right, inject mock and set it up before you call any code utilizing it.

这篇关于打破局部依赖关系以对void方法进行单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆