【问题标题】:Wiring dependencies in a Spring unit test without using @RunWith在不使用 @RunWith 的情况下在 Spring 单元测试中连接依赖项
【发布时间】:2023-04-09 19:01:01
【问题描述】:

我正在使用 spring 3 mvc/security 框架。

我创建了一个 Controller 类,它引用了要从中加载数据的存储库。类用@Controller注解,repository类用@Repository注解,repository的实例是@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(){
}
}

【问题讨论】:

  • 那么在控制器中创建 getter/setter 是最佳实践吗?

标签: java spring unit-testing integration-testing


【解决方案1】:

我个人倾向于使用@Simon's approach,而不是公开setter,尽管这两种方法都可以。不过,仅仅为了测试而添加 setter 有点烦人。

另一种方法是使用 Spring's ReflectionTestUtils class 通过反射直接将依赖项插入到字段中,从而无需特殊的构造函数和设置器,例如

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

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

这是否仍然构成“集成测试”是你的决定(我不知道)。

【讨论】:

  • 我认为reflectionTestUtils 可能是我最好的选择。但就我而言,我的 repo 有一个自动装配的 entityManager,所以我必须弄清楚如何进行嵌套反射。
【解决方案2】:

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

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

public Controller() {
    super();
}

protected Controller(Repositoy repo) {
    this();
    this.repo = repo;
}

【讨论】:

  • 为什么不只有一个构造函数 @Autowired?而不是使用字段级自动装配?
  • 如果您使用 XML 配置,您只能使用 1 个带有 @Autowired 的构造函数。如果您使用基于 Java 的配置,则必须在 Java 中实例化类,并且有一个空的构造函数很方便。
【解决方案3】:

通常,我会提供 setter 仅用于测试目的,但如果您担心代码的使用者会不正确地使用它们,也许您想使用一种利用反射的方法。

我过去写过一个实用程序,它接受两个参数,一个目标对象和一个您在目标上设置的对象。

public static void set(Object target, Object setMeOnTarget) {
    //
}

你可以从这里做的是自省 target 的字段,寻找 Spring 支持的自动装配注释(@Autowired@Resource@Inject,甚至可能是@Value),看看是否setMeOnTarget可以分配给那个字段(我用Class.isAssignableFrom(Class))。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多