java 使用 Spring 进行单元测试与集成测试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/281758/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 11:46:01  来源:igfitidea点击:

Unit tests vs integration tests with Spring

javatddjunitspring-mvcintegration-testing

提问by matt b

I'm working on a Spring MVC project, and I have unit tests for all of the various components in the source tree.

我正在处理一个 Spring MVC 项目,并且我对源树中的所有各种组件进行了单元测试。

For example, if I have a controller HomeController, which needs to have a LoginServiceinjected into it, then in my unit test HomeControllerTestI simply instantiate the object as normal (outside of Spring) and inject the property:

例如,如果我有一个控制器HomeController,它需要LoginService注入一个,那么在我的单元测试中,HomeControllerTest我只是简单地实例化对象(在 Spring 之外)并注入属性:

protected void setUp() throws Exception {
    super.setUp();
    //...
    controller = new HomeController();
    controller.setLoginService( new SimpleLoginService() );
    //...
}

This works great for testing each component as an isolated unit - except now that I have a few dozen classes in the project, after writing a class and writing a successful unit test for it, I keep forgetting to update my Spring MVC context file that does the actual wiring-up in the deployed application. I find out that I forgot to update the context file when I deploy the project to Tomcat and find a bunch of NullPointers from non-wired-up beans.

这对于将每个组件作为一个独立的单元进行测试非常有用 - 除了现在我在项目中有几十个类,在编写一个类并为其编写成功的单元测试之后,我一直忘记更新我的 Spring MVC 上下文文件已部署应用程序中的实际接线。我发现当我将项目部署到 Tomcat 并从未连接的 bean 中找到一堆 NullPointers 时,我忘记更新上下文文件。

So, here are my questions:

所以,这里是我的问题:

  1. This is my first Spring project - is it normal to create unit tests for the individual beans, as I have done, and then create a second suite of tests (integration tests) to test that everything works as expected with the actual application context? Is there an established best practice for this?

  2. In addition, how do you separate the unit tests from the integration tests? I have all of the source code in src, the unit tests in test- should there be a 2nd test folder (such as test-integration) for integration test cases?

  1. 这是我的第一个 Spring 项目 - 像我所做的那样为单个 bean 创建单元测试,然后创建第二套测试(集成测试)来测试在实际应用程序上下文中一切正常吗?是否有既定的最佳实践?

  2. 此外,您如何将单元测试与集成测试分开?我有所有源代码src,单元测试在test- 是否应该有第二个测试文件夹(例如test-integration)用于集成测试用例?

Since this is my first Spring project, I'm curious how others usually go about doing this sort of thing - and rather than re-invent the wheel I rather ask the rest of the community.

由于这是我的第一个 Spring 项目,我很好奇其他人通常是如何做这种事情的——与其重新发明轮子,不如问问社区的其他人。

采纳答案by Ken Gentle

I can't speak to being a best practice, but here's what I've done in the past.

我不能说是最佳实践,但这是我过去所做的。

Unit tests:

单元测试:

  • Create unit tests for non-trivial beans (ie, most of your Spring related beans)
  • Use Mocks for injected services where practical (ie, most if not all the time).
  • Use a standard naming convention for these tests in the project testdirectory. Using Testor TestCaseas a prefix or suffix to the classname seems to be widely practiced.
  • 为重要的 bean(即大多数与 Spring 相关的 bean)创建单元测试
  • 在可行的情况下将 Mock 用于注入的服务(即,如果不是所有时间,则是大多数)。
  • 对项目test目录中的这些测试使用标准命名约定。使用TestTestCase作为类名的前缀或后缀似乎被广泛使用。

Integration Tests:

集成测试:

  • Create an AbstractIntegrationTestCasethat sets up a SpringWebApplicationContextfor use in intetgration test clases.
  • Use a naming convention for integration tests in the testdirectory. I've used IntTestor IntegrationTestas a prefix or suffix for these tests.
  • 创建一个AbstractIntegrationTestCase设置一个SpringWebApplicationContext用于集成测试类的。
  • test目录中的集成测试使用命名约定。我已经使用IntTestIntegrationTest作为这些测试的前缀或后缀。

Set up three Ant testtargets:

设置三个 Anttest目标:

  1. test-all (or whatever you want to name it): Run Unit and Integration Tests
  2. test: Run Unit tests (just because testseems to be the most common usage for unit testing
  3. test-integration: run the integration tests.
  1. test-all(或任何你想命名的):运行单元和集成测试
  2. test:运行单元测试(只是因为test似乎是单元测试最常见的用法
  3. 测试集成:运行集成测试。

As noted, you can use the naming conventions that make sense for your project.

如前所述,您可以使用对您的项目有意义的命名约定。

As to separating unit from integration tests into a separate directory, I don't think it matters as long as the developers and their toolscan find and execute them easily.

至于将单元与集成测试分离到一个单独的目录中,我认为只要开发人员及其工具可以轻松找到并执行它们就可以了。

As an example, the last Java project I worked on with Spring used exactly what is described above, with integration tests and unit tests living in the same testdirectory. Grails projects, on the other hand, explicitly separate unit and integration test directories under a general test directory.

例如,我与 Spring 合作的最后一个 Java 项目完全使用了上述内容,集成测试和单元测试位于同一test目录中。另一方面,Grails 项目在通用测试目录下明确分离单元和集成测试目录。

回答by Benjamin Wootton

A few isolated points:

几个孤立的点:

Yes, it's a common approach to Spring testing - seperate unit tests and integration tests where the former doesn't load any Spring context.

是的,这是 Spring 测试的常用方法 - 单独的单元测试和集成测试,前者不加载任何 Spring 上下文。

For your unit tests, maybe consider mocking to ensure that your tests are focussed on one isolated module.

对于您的单元测试,可以考虑模拟以确保您的测试集中在一个孤立的模块上。

If you're tests are wiring in a ton of dependencies then they aren't really unit tests. They're integration tests where you are wiring of dependencies using new rather than dependency injection. A waste of time and duplicated effort when your production application uses Spring!

如果您的测试连接了大量依赖项,那么它们就不是真正的单元测试。它们是集成测试,您可以使用 new 而不是依赖注入来连接依赖项。当您的生产应用程序使用 Spring 时,浪费时间和重复工作!

Basic integration tests to bring up your Spring contexts are useful.

用于启动 Spring 上下文的基本集成测试很有用。

The @required annotation may help you to ensure you catch required dependencies in your Spring wiring.

@required 注释可以帮助您确保在 Spring 接线中捕获所需的依赖项。

Maybe look into Maven which will give you explicit phases to bind your unit and integration tests on to. Maven is quite widely used in the Spring community.

也许看看 Maven,它会给你明确的阶段来绑定你的单元和集成测试。Maven 在 Spring 社区中得到了相当广泛的使用。

回答by krosenvold

A lot of the tedious double-book-keeping with spring goes away if you also switch to a purely annotated regime, where you annotate all your beans with @Component, @Controller, @Service and @Repository. Just add @Autowired to the attributes you need to get injected.

如果您还切换到纯注释机制,使用 @Component、@Controller、@Service 和 @Repository 对所有 bean 进行注释,那么 Spring 的许多繁琐的双簿记都会消失。只需将 @Autowired 添加到您需要注入的属性中即可。

See section 3.11 of the spring reference manual. http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-annotation-config

请参阅弹簧参考手册的第 3.11 节。http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-annotation-config

On a related note, we have been using the division Unit/Integratrion tests that KenG describe. In my most recent regime we have also introduced a third "class" of tests, "ComponentTests". These run with full spring wiring, but with wired stub implementations (using component-scan filters and annotations in spring).

与此相关的是,我们一直在使用 KenG 描述的划分单元/集成测试。在我最近的制度中,我们还引入了第三个“类”测试,“ComponentTests”。这些使用完整的弹簧接线运行,但使用有线存根实现(在 spring 中使用组件扫描过滤器和注释)。

The reason we did this was because for some of the "service" layer you end up with an horrendous amount of hand-coded wiring logic to manually wire up the bean, and sometimes ridiculous amounts of mock-objects. 100 lines of wiring for 5 lines of test is not uncommon. The component tests alleviate this problem.

我们这样做的原因是因为对于某些“服务”层,您最终需要大量的手工编码布线逻辑来手动连接 bean,有时还有数量可笑的模拟对象。5线测试100线布线并不少见。组件测试缓解了这个问题。

回答by MetroidFan2002

Use the InitializingBean interface (implements a method "afterPropertiesSet") or specify an init-method for your beans. InitializingBean is typically easier because you don't need to remember to add the init method to your beans.

使用 InitializingBean 接口(实现一个方法“afterPropertiesSet”)或为你的 bean 指定一个 init-method。InitializingBean 通常更容易,因为您不需要记住将 init 方法添加到您的 bean。

Use afterPropertiesSet to ensure everything is injected as non-null, if it is null, throw an Exception.

使用 afterPropertiesSet 确保所有内容都作为非空注入,如果为空,则抛出异常。

回答by Paul McKenzie

With regard to running unit tests separately from integration tests, I put all the latter into an integration-test directory and run them using IDE/Ant using an approach like this. Works for me.

关于从集成测试单独运行单元测试,我把所有的后者为集成测试目录,并使用IDE /蚂蚁使用类似的方法运行它们。对我来说有效。

回答by Ali

the difference between unit test and integration test is , unit test does not necessarily load your context, you are focusing on the code which you have written - it works fails fast , that is with and without exceptions, by mocking any depends calls in it. But in case of integration tests , you load context and perform end to end test like actual scenarios.

单元测试和集成测试之间的区别在于,单元测试不一定加载您的上下文,您专注于您编写的代码 - 通过模拟其中的任何依赖调用,它的工作速度很快,即有无异常。但是在集成测试的情况下,您加载上下文并像实际场景一样执行端到端测试。

回答by sblundy

When I've created integration tests for web applications, I've put them in a separate directory. They are built using jUnit or TestNG and interact with the system under test using something like Seleniumthat hits the web pages as if they were users. The cycle would go like this: compile, run unit tests, build the web app, deploy it to a running server, execute the tests, undeploy the app, and report results. The idea is to test the whole system.

当我为 Web 应用程序创建集成测试时,我将它们放在一个单独的目录中。它们是使用 jUnit 或 TestNG 构建的,并使用Selenium 之类的东西与被测系统交互,这些东西就像用户一样点击网页。循环过程如下:编译、运行单元测试、构建 Web 应用程序、将其部署到正在运行的服务器、执行测试、取消部署应用程序并报告结果。这个想法是测试整个系统。