【问题标题】:How to test/Junit class using AnnotationConfigApplicationContext如何使用 AnnotationConfigApplicationContext 测试/Junit 类
【发布时间】:2020-07-01 18:24:36
【问题描述】:

我有一个使用 AnnotationConfigApplicationContext 的 servlet,我想测试这个类。我如何模拟AnnotationConfigApplicationContext 或者有没有办法在课堂上进行测试。由于非常具体的原因,我不想使用 spring-auto-mock。

下面是代码

 @WebServlet("/Application")
public class Application extends HttpServlet {
    private static final long serialVersionUID = 1L;
    
    
    private static final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String name = request.getParameter("name");
        String birthPlace = request.getParameter("birthPlace");
        PersonData person = new PersonData();
        person.setBirthPlace(birthPlace);
        person.setName(name);
        PersonDao dao = context.getBean(PersonDao.class);
        dao.insertPerson(person);
    }

}

@Configuration
@ComponentScan(basePackages = { "com.test.*" })
public class JavaConfig {

    @Bean
    public NamedParameterJdbcOperations getLettuceConnectionFactory() {
        return new NamedParameterJdbcTemplate(mysqlDataSource());
    }

    public DataSource mysqlDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/springjdbc");
        dataSource.setUsername("guest_user");
        dataSource.setPassword("guest_password");
        return dataSource;
    }
}

下面是我目前写的代码

public class ApplicationTest {
@Mock
AnnotationConfigApplicationContext context;

@Test
public void testApplication() throws Exception{
    Application app = new Application();
    PowerMockito.whenNew(AnnotationConfigApplicationContext.class).withAnyArguments().thenReturn(context);
    app.process();
}

}

我看到 JavaConfig 中的所有 bean 都在尝试生成,因为我将无法从 Junit 访问数据库,bean 创建失败,但我不希望首先创建 bean。

我是否正确启动了 AnnotationConfigApplicationContext 的模拟? 问题是由于AnnotationConfigApplicationContextprivatestatic 字段引起的吗? 我该如何处理这种情况。

如果我删除 static final 字段,是否可以在没有 Power Mockito 的情况下实现上述类的 junit 测试?

【问题讨论】:

  • 为什么?还有像Application 这样的类吗?正如我首先认为它有缺陷(通常当某些东西难以测试时,设计有问题是好的经验法则)。
  • 只有一个Application类
  • 尽管如此,它还是有缺陷的,这不是你应该使用 Spring 的方式。
  • 此类课程的可能解决方案是什么。由于它部署为独立代码,我需要使用 main 方法。我只想启动一次 spring 。我可以使某个类的 AnnotationConfigApplicationContext 实例变量,但我需要通过 main 方法启动 thtat 类,这意味着每次调用 main 方法时都会加载 bean。
  • 为什么main方法会被多次调用?这是运行程序的引导方法,您通常运行一次,然后保持运行或重新启动。

标签: java spring junit mockito powermockito


【解决方案1】:

您将无法使用当前实现模拟 AnnotationConfigApplicationContext。您将需要使用依赖注入。像这样在你的 Java Config 类中创建一个 @Bean。

@Bean
public AnnotationConfigApplicationContext getAnnotationConfigApplicationContext() {
  return new AnnotationConfigApplicationContext(JavaConfig.class);
}

然后在您的应用程序类中:

@WebServlet("/Application")
public class Application extends HttpServlet {
    private static final long serialVersionUID = 1L;
    
    **private final AnnotationConfigApplicationContext context;**

    **Application(AnnotationConfigApplicationContext annotationConfigApplicationContext) {
      this.annotationConfigApplicationContext = annotationConfigApplicationContext;
    }**

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       // code here
    }

}

M.迪纳姆是对的。这不是 Spring 应该使用的方式。

正确的做法是将 PersonDao 注入 Application 类。然后,您将在 ApplicationUnitTest 中模拟 PersonDao 类。

要做到这一点,它看起来像这样:

@WebServlet("/Application")
public class Application extends HttpServlet {
    private static final long serialVersionUID = 1L;
    
    **private final PersonDao dao;**

    **Application(PersonDao dao) {
      this.dao= dao;
    }**

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       String name = request.getParameter("name");
        String birthPlace = request.getParameter("birthPlace");
        PersonData person = new PersonData();
        person.setBirthPlace(birthPlace);
        person.setName(name);
       
        dao.insertPerson(person);
    }
}

你的测试看起来像这样:

public class ApplicationTest {

PersonDao personDao = mock(PersonDao.class);
Application app = new Application(personDao);

@Test
public void testApplication() throws Exception{
    doNothing().when(personDao).insert(any());
    
    app.doPost(request, response);
    verify(personDao).insert(person);
    // fill in the details
    // not sure what app.process is supposed to be
}

出于这样的原因,Spring 框架具有 MockMvc。它使测试中与端点的交互更容易。

【讨论】:

  • 我不认为构造函数 Application(AnnotationConfigApplicationContext annotationConfigApplicationContext) 会被调用,如果我错了请告诉我
猜你喜欢
  • 2020-02-10
  • 1970-01-01
  • 1970-01-01
  • 2017-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-26
  • 1970-01-01
相关资源
最近更新 更多