44

我的代码:

@Component
public class A {
    @Autowired
    private B b;

    public void method() {}
}

public interface X {...}

@Component
public class B implements X {
    ...
}

我想在 A 类隔离测试。我必须模拟 B 类吗?如果是,如何?因为它是自动装配的,并且没有设置器可以发送模拟对象。

4

4 回答 4

83

我想在隔离类 A 中测试。

您绝对应该模拟 B,而不是实例化和注入 B 的实例。重点是测试 A 是否 B 工作,因此您不应该让可能损坏的 B 干扰 A 的测试。

也就是说,我强烈推荐Mockito。随着模拟框架的发展,它非常易于使用。您将编写如下内容:

@Test
public void testA() {
    A a = new A();
    B b = Mockito.mock(B.class); // create a mock of B
    Mockito.when(b.getMeaningOfLife()).thenReturn(42); // define mocked behavior of b
    ReflectionTestUtils.setField(a, "b", b); // inject b into the B attribute of A

    a.method();

    // call whatever asserts you need here
}
于 2010-09-08T05:01:26.547 回答
18

这是我如何使用 Spring 3.1、JUnit 4.7 和 Mockito 1.9 进行测试的示例:

FooService.java

public class FooService {
    @Autowired private FooDAO fooDAO;
    public Foo find(Long id) {
        return fooDAO.findById(id);
    }
}

FooDAO.java

public class FooDAO {
    public Foo findById(Long id) {
        /* implementation */
    }
}

FooServiceTest.java

@RunWith(MockitoJUnitRunner.class)
public class FooServiceTest {
    @Mock private FooDAO mockFooDAO;
    @InjectMocks private FooService fooService = new FooService();

    @Test public final void findAll() {
        Foo foo = new Foo(1L);
        when(mockFooDAO.findById(foo.getId()).thenReturn(foo);

        Foo found = fooService.findById(foo.getId());
        assertEquals(foo, found);
    }
}
于 2012-07-23T01:40:31.590 回答
15

ReflectionTestUtils.setField您可以使用 Spring (或 junit 扩展)通过反射注入该字段,PrivateAccessor或者您可以创建一个模拟应用程序上下文并加载它。尽管对于简单的单元(非集成)测试,我更喜欢使用反射来简化。

于 2010-09-07T17:26:18.357 回答
0

这个论坛讨论对我来说很有意义。您可以将私有成员 b 声明为由 B 类实现的 InterfaceB 类型(即:面向服务),然后声明 MockB 类也将实现相同的接口。在您的测试环境应用程序上下文中,您声明 MockB 类和您的生产应用程序上下文,您声明普通 B 类,在任何一种情况下,都不需要更改 A 类的代码,因为它将自动连接。

于 2010-09-07T17:34:53.187 回答