简体   繁体   English

从单元测试到集成测试的有效过渡

[英]Effective transition from unit testing to integration testing

I'm currently investigating how we should perform our testing in an upcoming project. 我正在研究如何在即将开展的项目中执行测试。 In order to find bugs early in the development process, the developers will write unit tests before the actual code (TDDish). 为了在开发过程的早期发现错误,开发人员将在实际代码(TDDish)之前编写单元测试。 The unit tests will focus, as they should, on the unit (a method in this case) in isolation so dependencies will be mocked etc etc. 单元测试将单独关注单元(在这种情况下是一种方法),因此依赖性将被模拟等等。

Now, I also would like to test these units when they interact with other units and I was thinking that there should be a effective best practice to do this since the unit tests have already been written. 现在,我还想在与其他单位交互时对这些单元进行测试,我认为应该有一个有效的最佳实践,因为已经编写了单元测试。 My thought is that the unit tests will be reused but the mocked objects will be removed and replaced with real ones. 我的想法是单元测试将被重用,但被模拟的对象将被删除并替换为真实的对象。 The diffent ideas I have right now is: 我现在的不同想法是:

  • Use a global flag in each test class that decides if mock objects should be used or not. 在每个测试类中使用全局标志,该标志决定是否应使用模拟对象。 This approach will require several if statements 这种方法需要几个if语句
  • Use a factory class that either creates a "instanceWithMocks" or "instanceWithoutMocks". 使用创建“instanceWithMocks”或“instanceWithoutMocks”的工厂类。 This approach might be troublesome for the new developers to use and requires some extra classes 这种方法对于新开发人员来说可能很麻烦并且需要一些额外的类
  • Separate the integration tests from the unit tests in different classes. 将集成测试与不同类中的单元测试分开。 This will however require a lot of redundant code and maintaining the test cases will be twice the work 然而,这将需要大量冗余代码并且维护测试用例将是工作的两倍

The way I see it all of these approaches have pros and cons. 我认为所有这些方法的方式都有利有弊。 Which of these would be preferred and why? 哪个是首选,为什么? And is there a better way to effective transition from unit testing to integration testing? 有没有更好的方法从单元测试到集成测试的有效过渡? Or is this usually done in some other way? 或者这通常以其他方式完成?

I would go for the third option 我会选择第三种选择

  • Seperate the integration tests from the unit tests in different classes. 从不同类中的单元测试中分离集成测试。 This will however require alot of redundant code and maintaining the test cases will be twice the work 然而,这将需要大量冗余代码并且维护测试用例将是工作的两倍

This is because unit tests and integration tests have different purposes. 这是因为单元测试和集成测试有不同的目的。 A unit test shows that an individual piece of functionality works in isolation. 单元测试表明,单独的功能单独工作。 An integration test shows that different pieces of functionality still work when they interact with each other. 集成测试表明,当它们彼此交互时,不同的功能仍然有效。

So for a unit test you want to mock things so that you are only testing the one piece of functionality. 因此,对于单元测试,您希望模拟事物,以便您只测试一个功能。

For an integration test mock as little as possible. 对于集成测试模拟尽可能少。

I would have them in separate projects. 我会把它们放在不同的项目中。 What works well at my place is to have a unit test project using NUnit and Moq. 在我的地方运作良好的是使用NUnit和Moq进行单元测试项目。 This is written TDD as the code is written. 编写代码时写入TDD。 The integration tests are Specflow/Selenium and the feature files are written with the help of the product owner in the planning session so we can verify that we are delivering what the owner wants. 集成测试是Specflow / Selenium,功能文件是在计划会话中借助产品所有者编写的,因此我们可以验证我们是否提供了所有者想要的内容。

This does create extra work in the short term but leads to fewer bugs, easier maintenance, and delivery matching requirements. 这确实可以在短期内创造额外的工作,但可以减少错误,更容易维护和交付匹配要求。

An IoC container like Ninject/Autofac/StructureMap may be of use to you here. 像Ninject / Autofac / StructureMap这样的IoC容器可能对您有用。 The unit tests can resolve the system-under-test through the container, and it is simply a matter of registration whether you have mocks or real objects registered. 单元测试可以通过容器解决被测系统,只需注册是否有注册的模拟或真实对象。 Similar to your factory approach, but the IoC container is the factory. 与您的工厂方法类似,但IoC容器是工厂。 New developers would need a little training to understand, but that's the case with any complex system. 新开发人员需要一些培训才能理解,但任何复杂系统都是如此。 The disadvantage to this is that the registration scenarios can become fairly complicated, but it's hard to say for any given system whether they'd be too complicated without trying it out. 这样做的缺点是注册场景可能变得相当复杂,但是对于任何给定的系统来说,如果没有尝试它们是否复杂就很难说。 I suspect this is the reason you haven't found any answers that seem definitive. 我怀疑这是你没有找到任何看似确定的答案的原因。

The integration tests should be different classes than your unit tests since you are testing a different behavior. 由于您正在测试不同的行为,因此集成测试应该是与单元测试不同的类。 The way that I think of integration tests is that they are the ones that you execute when trying to make sure that everything works together. 我认为集成测试的方式是,它们是您在尝试确保所有内容协同工作时执行的。 They would be using inputs to portions of the application and making sure that the expected output is returned. 他们将使用输入部分应用程序并确保返回预期的输出。

I think you are messing up the purpose of unit testing and integration testing. 我认为你搞砸了单元测试和集成测试的目的。 Unit testing is for testing a single class - this is low level API. 单元测试用于测试单个类 - 这是低级API。 Integration testing is testing how classes cooperate. 集成测试正在测试类的协作方式。 This is another higher level API. 这是另一个更高级别的API。 Normally, you can not reuse unit tests in integration testing because they represent different level of system view. 通常,您不能在集成测试中重用单元测试,因为它们代表不同级别的系统视图。 Using spring context may help with setting up environment for integration testing. 使用spring上下文可能有助于为集成测试设置环境。

I'm not sure reusing your unit tests with real objects instead of mocks is the right approach to implementing integration tests. 我不确定将单元测试重用于真实对象而不是模拟是实现集成测试的正确方法。

The purpose of a unit test is to verify the basic correctness of an object in isolation from the outside world. 单元测试的目的是验证与外界隔离的对象的基本正确性。 Mocks are there to ensure that isolation. 模拟是为了确保隔离。 If you substitute them for real implementations, you'll actually end up testing something completely different - the correctness of large portions of the same chain of objects, and you're redundantly testing it many times . 如果你用真正的实现代替它们,你实际上最终会测试完全不同的东西 - 同一对象链的大部分的正确性,并且你多次对它进行冗余测试。

By making integration tests distinct from unit tests, you'll be able to choose the portions of your system you want to verify - generally, it's a good idea to test parts that imply configuration, I/O, interation with third-party systems, the UI or anything else that unit tests have a hard time covering. 通过使集成测试与单元测试不同,您将能够选择要验证的系统部分 - 通常,测试暗示配置,I / O,与第三方系统的交互的部分是个好主意, UI或其他任何单元测试都难以覆盖的东西。

I agree to most other answers, that unittesting should be seperate from integrationtesting (option 3) . 我同意大多数其他答案,单元测试应该与集成测试分开(选项3)

But i do not agree to your contra arguments: 但我不同意你的反对意见:

[...] This (seperating unit from integration testing) will however require a lot of redundant code and maintaining the test cases will be twice the work . [...]这个(来自集成测试的分离单元)将需要大量冗余代码,并且维护测试用例将是工作的两倍

Generating objects with test data can be a lot of work but this can be refactored to test-helper clases aka ObjectMother that can be used from unit and integration testing so there is no need for redundancy there 使用测试数据生成对象可能需要大量工作,但这可以重构为测试助手,即ObjectMother ,可以在单元和集成测试中使用,因此不需要冗余

In unit tests you check different conditions of the class under tests. 在单元测试中,您可以检查测试中的类的不同条件。

For integration testing it is not neccessary to re-check every of these special cases. 对于集成测试,不需要重新检查每个特殊情况。 Instead you check that the components work together. 而是检查组件是否一起工作。

Example

You may have unit-tests for 4 different situations where an exception is thrown. 您可能会针对引发异常的4种不同情况进行单元测试。 For the integration it is not neccessary to re-test all 4 conditions One exception-related integration test is enough to verify that the integrated system can handle exceptions. 对于集成,不需要重新测试所有4个条件。与异常相关的集成测试足以验证集成系统是否可以处理异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM