java - 打破本地依赖以单元测试无效方法

标签 java unit-testing tdd mockito legacy

我正在练习 mockito,但我对如何测试依赖于对本地对象中方法的调用的方法有点困惑。 请参阅以下示例:

public class Worker {          

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

这个 worker ,他不干活,反而喜欢喝酒。但是我想添加一个测试来证明他在工作时喝酒。但是没有办法这样做,因为我必须在调用方法 work 时验证方法 drink() 被调用。我想你同意我的看法,这是不可能测试的,所以我需要在开始测试之前打破依赖关系。 这是我的第一个疑问,您认为打破这种依赖的最好方法是什么? 如果我只是将 vodka 对象的范围更改为全局,我认为不会很好(我不想将它暴露给类(class)的其他部分)。我想过创建一个工厂,像这样:

public class Worker {          

    private VodkaFactory vodkaFactory = new VodkaFactory();


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

我不确定我是否正确地打破了依赖关系,但我现在想做的是测试在执行 work() 时调用了 drink() 方法。 我没有运气就试过了:

@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();
    }

我模拟了工厂,什么时候会检测到工厂创建了一个新的 Vodka 对象。但是当我想验证该方法是否调用 1 次方法 drink() 时,mockito 告诉我:

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.

我没有正确 stub 或者我做错了什么。你能帮我完成这个测试,并说明测试这种不可测试方法的最佳方法是什么吗?

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

更新:

我正在按照建议在 work() 之前调用 when() 并且我正在尝试允许从外部设置工厂类:

@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()

的行

抱歉,我仍然对问题所在感到困惑。

最佳答案

你的 worker 在这里创建他自己的工厂类:

private VodkaFactory vodkaFactory = new VodkaFactory();

您正在创建的模拟完全脱离了工作实例,因此缺乏交互。为了让它工作,工厂必须从“外部”注入(inject) worker ,比如通过 constructor injection .

如果这是遗留代码,您可以使用反射将私有(private)工厂实例替换为模拟实例。

正如 JB Nizet 在评论中指出的那样,您的模拟设置是在调用 work 之后进行的。为了把事情做好,在调用任何使用它的代码之前注入(inject)模拟并设置它。

关于java - 打破本地依赖以单元测试无效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15350239/

相关文章:

unit-testing - Resharper 10 : Unit test output window is broken

testing - (错误)理解 Smalltalk 和 TDD

Java通过格式化文件输入

java - Android - Glide 库内存不足异常

java - doGet 方法在 tomcat 7 中运行的 servlet 中被调用两次,并使用 IntelliJ Idea 12 创建

java - 我的代码有什么问题? (执行代码时崩溃)

c# - 我怎样才能找出哪个对象创建了这个对象

c++ - OpenGL 如何进行单元测试?

unit-testing - 使用 RGR 方法时,属性测试是否应该与单元测试一起运行?

ruby-on-rails - 如何干燥这个 rspec 测试?