3

我正在使用 Struts2 框架,并希望对execute以下方法进行单元测试:

public String execute() {
    setDao((MyDAO) ApplicationInitializer.getApplicationContext().getBean("MyDAO"));
    setUserPrincipal(); //fetches attribute from request and stores it in a var
    setGroupValue(); //
    setResults(getMyDao().getReportResults(getActionValue(), getTabName());
    setFirstResultSet((List) getResults()[0]);
    setSecondResultSet((List) getResults()[1]);
    return SUCCESS;
}

如您所见,大部分逻辑与数据库相关。那么我将如何对这个功能进行单元测试呢?我想通过模拟HTTPServletRequest其中的几个请求变量来进行单元测试。

我的问题是:

  • 我如何伪造/模拟请求变量,就好像它来自浏览器一样
  • 我的单元测试是否应该调用实际的 DAO 并确保数据返回?
  • 如果是这样,我如何从单元测试中调用 DAO,因为 DAO 绑定到服务器,因为 jndi 池设置驻留在应用程序服务器上。

我很感激任何展示如何真正做到这一点的书/文章。

4

3 回答 3

6

您向我们展示的代码不足以完全回答您的问题。

逐行

setDao((MyDAO) ApplicationInitializer.getApplicationContext().getBean("MyDAO"));

这是最难的路线,因为它使用静态方法。我们需要看看是如何ApplicationInitializer工作的。在理想世界中,该getApplicationContext()方法应该返回模拟的ApplicationContext. 这个模拟应该在何时MyDAO返回getBean("MyDAO")完全有能力处理这个问题,以及所有其他模拟框架。


setUserPrincipal(); //fetches attribute from request and stores it in a var

请求从何而来?它是否注入到动作类中?如果是这样,只需注入模拟请求对象,例如MockHttpServletRequest.


setGroupValue(); //

和上面一样吗?请提供更多详细信息,这种方法实际上是做什么的?


setResults(getMyDao().getReportResults(getActionValue(), getTabName());

getReportResults()当使用给定的参数调用时,您之前创建的模拟应该返回一些东西。


setFirstResultSet((List) getResults()[0]);
setSecondResultSet((List) getResults()[1]);

我猜下面的方法在动作类上设置了一些字段。因为您可以完全控制从 mocked 返回的内容getReportResults(),所以这不是问题。


return SUCCESS;

您可以断言是否SUCCESS是执行结果。


现在一般

我如何伪造/模拟请求变量,就好像它来自浏览器一样

见上文,Spring 中内置了一个 mock。

我的单元测试是否应该调用实际的 DAO 并确保数据返回?

如果你的单元测试调用真正的 DAO,它就不再是单元测试。这是一个集成测试。

如果是这样,我如何从单元测试中调用 DAO,因为 DAO 绑定到服务器,因为 jndi 池设置驻留在应用程序服务器上。

这意味着您正在进行集成测试。在这种情况下,您应该使用像这样的内存数据库,这样您仍然可以在服务器上运行测试。您必须以某种方式配置您的应用程序以DataSource从不同的位置获取。


最后说明

本质上,您应该将所有内容的模拟注入到您的 Struts 动作类中。您可以告诉模拟在调用时返回任何值。然后,在调用之后execute(),您可以验证给定的方法被调用,字段设置和结果值是否正确。考虑将其拆分为几个测试。


代码审查

  • Struts 2 与 Spring 完美集成。如果您利用该功能,Spring 容器将自动注入MyDAO您的操作类。第一行已过时。
于 2012-05-23T18:55:13.873 回答
1

这段代码很难进行单元测试,因为你没有按预期使用 Spring(即作为依赖注入框架),而是将它用作工厂。依赖注入正是用于避免您正在执行的这种难以测试的 bean 查找。DAO 应该被注入到您的对象中。这样,您可以在对对象进行单元测试时注入模拟 DAO。

此外,此逻辑根本与数据库无关。DAO 包含与数据库相关的逻辑。此操作使用DAO,因此 DAO 是另一个单元(应在其自己的单元测试中进行测试)。因此,您应该注入一个模拟 DAO 来对该方法进行单元测试。

最后,这个方法不使用 HttpServletRequest (至少不直接使用),所以我不明白你为什么需要使用假请求。您可以模拟使用请求的 setXxx 方法。

于 2012-05-23T18:53:57.037 回答
0
  1. 与其简单地模拟HTTPServletRequest,不如模拟对应用程序本身的实际自动目标请求?查看Selenium,它可以让您做到这一点。

  2. 对于测试 DAO(集成测试),您可以使用HSQLDB在内存中创建数据库,这将允许您从测试中创建/删除对象,并确保它们被正确地持久化/检索。HSQLDB 的优势在于您的测试将比使用实际数据库运行得快得多。当需要提交代码时,您可以针对您的实际数据库运行测试。通常,您会在 IDE 中设置不同的运行配置来促进这一点。

  3. 让注入的 daos 可用于测试的最简单方法是让单元测试类扩展AbstractJUnit4SpringContextTests. 然后,您可以使用@ContextConfiguration注释指向多个 xml 应用程序上下文文件,或者如果您使用基于注释的配置,请将其指向您的上下文文件,其中包含<context:annotation-config />声明。

于 2012-05-23T19:01:49.087 回答