Java模拟对象,无需依赖注入

14

我对在JUnit测试套件中嘲弄(mock)对象很感兴趣,但是我只发现使用依赖注入来注入(mock)对象的mock框架。然而,我希望能够在不需要注入(mock)对象的情况下,像Python中的@patch()一样嘲弄类/函数。

简单示例:

//dependency injection
public String bar(Foo foo) {
    return foo.foo(); //just pass in mock Foo object
}
//.... onto test code
Foo mockedFoo = <Mocked Foo object>;
String response = bar(mockedFoo);
assertEqual(response, <mockedFoo return value>);


//case I am looking for
public String bar() {
    Foo foo = new Foo(); //how to create mock object here?
    return foo.foo(); //or simply how to mock a single function?
}
//... onto test code
<force the Foo class or foo method to be mocked from here without touching bar() source code>
String response = bar();
assertEqual(response, <mocked response>);

https://dev59.com/8Wgv5IYBdhLWcg3wCcWZ - kamoor
使用一个库,例如 Mockito。或者在更简单的情况下,扩展 Foo 或者更好的是实现与 Foo 相同的接口来获得一个简单的模拟对象。 - mike
Mike,从查看Mockito来看,似乎仍然需要注入依赖项。请参见上面的编辑以增加清晰度。 - Brent Hronik
@Kamoor1982,那篇帖子的作者似乎在问与我相反的问题。 - Brent Hronik
有人知道使用 C# 而非 Java 的解决方案吗? - Vetras
2个回答

4
你可以使用Powermock来对测试类进行操作,在new被调用时返回一个模拟对象。 Powermock模拟构造函数教程 代码如下:
RunWith(PowerMockRunner.class)
@PrepareForTest( Bar.class )
public class BarTest {


@Test
public void test(){
   Foo mockedFoo = createMock(Foo.class);
   //set up mockedFoo here
   ...

   //This will make a call  to new Foo() inside Bar.class
   //return your mock instead of a real new one
   expectNew(Foo.class).andReturn(mockedFoo);

   ...
   replay(mockedFoo, File.class);

   Bar bar = new Bar();
   String response = bar.bar();

   assertEqual(response, <mocked response>);

   verify(mockedFoo, File.class);


}

}

如果我没记错的话,expectNew 只能在 EasyMock 中使用,而不能在 Mockito 中使用。对于 Mockito,请使用 whenNew。 - luca.vercelli

2
简单来说,您可以像这样模拟 Foo
public String bar() {
    Foo foo = Mockito.mock(Foo.class);
    return foo.foo();
}

这样做的问题在于,当您未定义调用模拟版本时#foo()应返回什么时,foo.foo()本质上不会执行任何操作。使用更完整的示例,您可以这样做:
class MyTest {

    Foo mockedFoo = Mockito.mock(Foo.class);

    @Before
    public void setUp() throws Exception {
        Mockito.when(mockedFoo.foo()).thenReturn("This is mocked!");
    }

    @Test
    public void testMock() {
        String returnedFoo = mockedFoo.foo();
        Assert.assertEquals("This is mocked!", returnedFoo);
    }
}

感谢您的建议,我已经修改了我的帖子以增加清晰度。看起来这个回答回答了一个与我所问的问题略有不同的问题,对此我感到抱歉。 - Brent Hronik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接