本文介绍了在单元测试中重用代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 REST Web 服务接口,它向下调用服务层,该服务层协调实体层中各种对象的创建、删除等.这些实体层对象最终映射到数据库记录.我有许多单元测试(在 nunit 中,它是一个 c# 应用程序)通过发送 http 请求来测试这个接口.

考虑我对创建某个实体层对象的 Web 服务请求的测试.我显然想通过检查它返回给我的 http 状态以及响应正文中的一些数据来验证 Web 服务是否认为请求已被正确处理.我还想独立验证是否已创建正确的数据库记录.我有几种方法(我能想到的)来做到这一点:

  • 最简单的方法是使用实​​体层中现有的阅读器"类来读取和验证数据库条目.这很容易,因为它们为它们处理的实体合并了验证和一致性逻辑,并且使用它们很简单.不过,我对此感到不安,因为我将使用我正在测试的代码作为测试的一部分.这似乎违反了一些关注点分离的原则,并且还引入了实体层错误导致对象创建失败但在单元测试中似乎成功的可能性.

  • 或者,测试代码可以直接进入数据库并自行进行检查.但是随后我在测试中嵌入了有关对象存储和一致性规则的详细信息——如果这些细节发生变化,这会使测试变得脆弱,并且还有效地意味着在单元测试中重新实现我已经在实体中编写的代码层.

我想知道人们如何看待这些(可能还有其他)选项所涉及的权衡,以及最佳实践(如果有的话)是什么?我不确定是否有正确或错误的答案,但我已经想了一段时间并且对其他意见感兴趣.

编辑

为了澄清,我为服务层和实体层保存了单独的测试套件.我所表达的担忧——在测试中使用经过测试的代码——也适用于这些测试.

解决方案

我们看到两个不同的测试,一个是服务方法的测试,一个是 webclient 的测试.

为了测试服务方法(如阅读器),您可能希望创建一个具有预定义值(测试数据)的数据库,调用阅读器并测试,如果阅读器输出以所需方式与测试数据匹配.

一旦您测试了服务方法,您就可以进入下一个测试级别并测试 Web 客户端,再次使用相同的测试数据,但现在测试 Web 客户端上显示的数据是否以所需方式与测试数据匹配.在这个测试级别上,您可以信任"读者(因为他们之前已经过测试).

如果将单元测试"和集成测试"分开,也许你会觉得更舒服.对于单元测试,验证编译单元是否按要求工作.这可能是在测试阅读器:您用定义的数据填充数据库,调用 findAll()(或其他东西),并断言测试数据和只有测试数据在结果中.findAll()>

另一个测试是集成测试 - 您可以验证服务层和实体层是否按预期协同工作.与测试 Web 客户端相同:您验证客户端/服务层是否按要求工作.

对于集成测试,我认为没有任何理由不使用(经过测试的)服务层方法.

I have a REST web-service interface that calls-down to a service layer which orchestrates the creation, deletion, etc. of various objects in an entity-layer. These entity-layer objects ultimately map to database records. I have a number of unit tests (in nunit, it a c# application) that test this interface by sending http requests.

Consider my testing of a web service request that creates a some entity-layer object. I obviously want to verify that the web service considers the request to have been processed correctly, by checking the http status that it returns to me plus some data in the response body. I also want to independently verify that the correct database records have been created. I have a couple of ways (that I can think of) to do this:

  • The easiest way is to use existing 'reader' classes in the entity layer to read and validate the database entries. This is easy because they incorporate the validation and consistency logic for the entities they deal with, and using them is simple. I am uneasy about this, though, because I would be using the code I'm testing as part of the test. This seems to violate some principle of separation of concerns, and also introduce the possibility of an entity-layer bug causing the object creation to fail but appear to the unit test to have succeeded.

  • Alternatively, the test code could go straight to the database and do the checks itself. But then I'm embedding details about object storage and consistency rules in the test - which makes the test brittle if those details change, and also effectively means re-implementing, in the unit tests, the code I've already written in the entity layer.

I wonder what people think of the trade-offs involved with these (and maybe other) options, and what (if any) is the best practice? I'm not sure if there is a right or wrong answer, but I've wondered about it for a while and interested in other opinions.

EDIT

To clarify, I save separate test suites for the service-layer and the entity-layer. The concerns I have expressed -- using tested code in a test -- also apply to these tests.

解决方案

We see two different tests, a test of the service methods and a test of the webclient.

For testing the service methods (like a reader), you may want to create a database with predefined values (test data), call the reader, and test, if the readers output matches the test data in the required way.

Once you've tested the service methods, you can move to the next test level and test the web client, again using the same test data but now testing if data shown on the web client matches the test data in the required way. On this test level, you can "trust" the readers (because they have been tested before).


Maybe you feel more comforable if you separate between "unit testing" and "integration testing". For unit testing, verify that a compilation unit works as required. This could be testing the reader: you populate the database with defined data, call findAll() (or something else), and assert that the test data and only the test data is in the result.

The other test is an integration test - there you verify, that service layer and entity layer work together as expected. Same with testing the web client: you verify that the client / service layer works as required.

And for integration tests I don't see any reason to not use (tested) service layer methods.

这篇关于在单元测试中重用代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-18 23:41