Java 在不使用@RunWith的Spring单元测试中连接依赖项

Java 在不使用@RunWith的Spring单元测试中连接依赖项,java,spring,unit-testing,integration-testing,Java,Spring,Unit Testing,Integration Testing,我使用的是Spring3MVC/安全框架 我创建了一个控制器类,该类具有对要从中加载数据的存储库的引用。类用@Controller注释,存储库类用@repository注释,respository的实例是@Autowired 然而,当我尝试进行单元测试时,autowired实例抛出一个空指针异常 现在,我明白了,因为它是自动连接的,所以需要在spring上下文中进行提取。但是我觉得如果我使用@RunsWith(),那么它就变成了一个集成测试。我真的很想将此方法的集成测试(使用@RunsWith)

我使用的是Spring3MVC/安全框架

我创建了一个控制器类,该类具有对要从中加载数据的存储库的引用。类用
@Controller
注释,存储库类用
@repository
注释,respository的实例是
@Autowired

然而,当我尝试进行单元测试时,autowired实例抛出一个空指针异常

现在,我明白了,因为它是自动连接的,所以需要在spring上下文中进行提取。但是我觉得如果我使用
@RunsWith()
,那么它就变成了一个集成测试。我真的很想将此方法的集成测试(使用
@RunsWith
)和单元测试分开。关于如何绕过这个空指针异常,有什么想法吗?在我的控制器类上创建getter/setter方法可以吗

存储库类:

@Repository
public class Repository{
 ....
}
控制器类:

@Controller
public class Controller{
@Autowired
private Repository repo;
....
public String showView(){
    repo.doSomething();
}
测试等级:

public ControllerTest {
@Test
public shouldDoTestOfShowView(){
}
}

通常,我提供setter只是为了测试目的,但是如果您担心代码的使用者不正确地使用它们,那么您可能希望使用一种利用反射的方法

我以前写过一个实用程序,它接受两个参数,一个是目标对象,另一个是在目标上设置的对象

public static void set(Object target, Object setMeOnTarget) {
    //
}
在这里,您可以对
target
字段进行内省,查找Spring支持的自动连接注释(
@Autowired
@Resource
@Inject
,甚至可能
@Value
),并查看是否可以将
setMeOnTarget
分配给该字段(我使用了
Class.isAssignableFrom(Class)


它可能有点脆弱(Spring突然停止支持这些注释…不太可能…),但它对我来说非常有效。

我总是编写两个构造函数。一个没有Spring的参数,一个有单元测试所有依赖项的受保护的

@Controller
public class Controller{
@Autowired
private Repository repo;

public Controller() {
    super();
}

protected Controller(Repositoy repo) {
    this();
    this.repo = repo;
}
我个人倾向于使用,而不是暴露二传者,尽管这两种方法都可以。不过,仅仅为了测试而添加setter有点烦人

另一种方法是使用反射直接将依赖项插入字段,这样就不需要特殊的构造函数和setter,例如

public ControllerTest {
   @Test
   public shouldDoTestOfShowView() {
      Controller controller = new Controller();
      Repository repository = new Repository();

      ReflectionTestUtils.setField(controller, "repo", repository); 
   }
}

这是否仍然构成“集成测试”是您的职责(我不知道)。

那么在控制器中创建getter/setter是最佳实践吗?为什么不只创建一个@Autowired的构造函数呢?如果使用XML配置,则只能使用一个带有@Autowired的构造函数,而不是使用字段级自动连接。如果你使用基于Java的配置,你必须用Java实例化这个类,并且有一个空的构造函数是很方便的。但在我的例子中,我的回购协议有一个自动连接的entityManager,所以我必须弄清楚如何进行嵌套反射。