Java 使用 mockito 模拟嵌套方法调用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41732361/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 23:37:40  来源:igfitidea点击:

mock nested method calls using mockito

javamethodsjunitmockingmockito

提问by Abhijeet

I have got 4 classes lets says A, B, C, D each calling on methods from another one.

我有 4 个类,可以说 A、B、C、D,每个类都调用另一个类的方法。

now I have mocked class A, and want to mock a method using mockito

现在我已经模拟了 A 类,并想使用 mockito 模拟一个方法

A a = Mockito.mock(A.class);

and want to get "foo" on recursive method calls like

并希望在递归方法调用上获得“foo”,例如

a.getB().getC().getD()should return "foo"

a.getB().getC().getD()应该回来 "foo"

I tried

我试过

when(a.getB().getC().getD()).thenReturn("foo");

when(a.getB().getC().getD()).thenReturn("foo");

but got nullPointerException

但得到了 nullPointerException

then I tried

然后我试过了

doReturn("foo").when(a.getB().getC().getD());

doReturn("foo").when(a.getB().getC().getD());

then I got org.mockito.exceptions.misusing.UnfinishedStubbingException:

然后我得到了 org.mockito.exceptions.misusing.UnfinishedStubbingException:

I know I can create objects of B, C and D, or can even write something like

我知道我可以创建 B、C 和 D 的对象,甚至可以写一些类似的东西

B b = mock(B.class) or A.setB(new B())

B b = mock(B.class) 或 A.setB(new B())

and so on.

等等。

But can't I do that in a single shot? Any help would be appreciated.

但是我不能一次性做到吗?任何帮助,将不胜感激。

采纳答案by Abhijeet

From the comments:

来自评论:

Adding RETURNS_DEEP_STUBS did the trick:

添加 RETURNS_DEEP_STUBS 可以解决问题:

A a = Mockito.mock(A.class, Mockito.RETURNS_DEEP_STUBS);

回答by GhostCat

The technical answer by Abhijeet is technically correct, but it is important to understand: you should notbe doing this.

Abhijeet 的技术回答在技术上是正确的,但重要的是要了解:您应该这样做。

Your "production" code is heavilyviolating the Law of Demeter: your class A should notknow that it has to get a B to get a C to get a D.

您的“生产”代码严重违反了迪米特法则:您的 A 班应该知道它必须获得 B 才能获得 C 才能获得 D。

That simply leads to super tightcoupling between all these classes. Not a good idea.

这只会导致所有这些类之间的超紧耦合。不是个好主意。

In that sense: you should see the fact that you need to do special things here to get your test working is actually as an indication that your production code does something that is out of the normal.

从这个意义上说:你应该看到你需要在这里做一些特殊的事情来让你的测试工作这一事实实际上表明你的生产代码做了一些不正常的事情。

So, instead of "fixing" your test setup, consider addressing the real problem. And that is the designof your production code!

因此,与其“修复”您的测试设置,不如考虑解决真正的问题。这就是您的生产代码设计

And for the record: getB().getC().getD() is not a "recursive" call; it is more of a "fluent" chaining of method calls. And as said: that is nota good thing.

为了记录: getB().getC().getD() 不是“递归”调用;它更像是一个“流畅”的方法调用链。正如所说:这不是一件好事。

回答by Nags

Try by creating mock of each of the nested object and then mock the individual method called by each of these object.

尝试创建每个嵌套对象的模拟,然后模拟每个这些对象调用的各个方法。

If the target code is like:

如果目标代码是这样的:

public Class MyTargetClass {

    public String getMyState(MyClass abc){

       return abc.getCountry().getState();
    }
}

Then to test this line we can create mocks of each of the individual nested objects like below:

然后为了测试这一行,我们可以为每个单独的嵌套对象创建模拟,如下所示:

public Class MyTestCase{

@Mock
private MyTargetClass myTargetClassMock;

@Mock
private MyClass myclassMockObj;

@Mock
private Country countryMockObj;

@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
}

    @Test
    public void test01(){

       when(myclassMockObj.getCountry()).thenReturn(countryMockObj);
       when(countryMockObj.getState()).thenReturn("MY_TEST_STATE");
       Assert.assertEquals("MY_TEST_STATE", myTargetClassMock.getMyState(myclassMockObj));
    }
}