使用Junit和EasyMock对使用自动装配符号的类进行单元测试?

时间:2012-03-21 15:37:55

标签: spring unit-testing dependency-injection junit mocking

我正在为一个标有@Autowired的几个字段的类编写一个单元测试。鉴于Spring正在自动解析这些字段的具体实现,我很难弄清楚如何在测试运行期间插入我的Mock对象(通过EasyMock创建)作为依赖项。在课堂上使用@Autowired意味着在该课程中缺少setter。有没有办法让我插入我的模拟对象而不在课堂上创建额外的setter?

这是我想要完成的一个例子:

public class SomeClassUnderTest implements SomeOtherClass{

@Autowired
private SomeType someType;

@Autowired
private SomeOtherType someOtherType;

@Override
public SomeReturnType someMethodIWouldLikeToTest(){
//Uses someType and someOtherType and returns SomeReturnType
}

}

以下是我在碰壁前制作Test类的方法:

public class MyTestClassForSomeClassUnderTest{
  private SomeType someType;
  private SomeOtherType someOtherType;

  @Before
  public void testSetUp(){
    SomeClassUnderTest someClassToTest = new SomeClassUnderTest();
    someType = EasyMock.createMock(SomeType.class);
    someOtherType = EasyMock.createMock(SomeOtherType.class);
    //How to set dependencies????
  }

  @Test
  public void TestSomeMethodIWouldLikeToTest(){
    //??????
  } 

}

向正确的方向努力将会很棒。

由于

3 个答案:

答案 0 :(得分:34)

您可以使用ReflectionTestUtils反射性地将依赖项直接注入字段,例如

ReflectionTestUtils.setField( testInstance, "fieldName", fieldValue );

有些人会争辩说,无论如何最好将类包装可见的setter方法添加到类中,仅由测试使用。或者,使用自动装配的构造函数而不是自动装配的字段,并将测试依赖项注入其中。

答案 1 :(得分:6)

虽然可以通过反射设置这些字段,但这样做会阻止您的开发工具查找这些字段的用法,并使您以后更难以重构SomeClassToTest

最好为这些字段添加公共设置器,并将@Autowired注释放在这些字段上。这不仅避免了反射,而且还阐明了类的外部接口,并确保您的单元测试仅使用此接口。我看到SomeClassToTest已经实现了SomeOtherClass接口,我假设SomeClassToTest的客户端只使用这个接口,所以在SomeClassToTest公共上设置setter几乎没有危险

更好的是,使用构造函数注入并使字段最终。您仍然可以在构造函数参数上使用@Autowired

答案 2 :(得分:2)

我不推荐已被接受的答案,即自己使用反射(没有模拟框架)。

从EasyMock的3.2版开始,您可以使用注释来定义模拟并将它们注入到被测试的类中。有关如何操作的完整说明,请参阅EasyMock的官方文档: http://easymock.org/user-guide.html#mocking-annotations

以下是上述网站的一个例子:

import static org.easymock.EasyMock.*;
import org.easymock.EasyMockRunner;
import org.easymock.TestSubject;
import org.easymock.Mock;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(EasyMockRunner.class)
public class ExampleTest {

  @TestSubject
  private ClassUnderTest classUnderTest = new ClassUnderTest(); // 2

  @Mock
  private Collaborator mock; // 1

  @Test
  public void testRemoveNonExistingDocument() {
    replay(mock);
    classUnderTest.removeDocument("Does not exist");
  }
}