问题描述
这个问题或多或少与编程语言无关.但是,由于这些天我主要使用 Java,因此我将从中提取示例.我也在考虑 OOP 的情况,所以如果你想测试一个方法,你需要一个方法类的实例.
This question is more or less programming language agnostic. However as I'm mostly into Java these days that's where I'll draw my examples from. I'm also thinking about the OOP case, so if you want to test a method you need an instance of that methods class.
单元测试的核心规则strong> 是它们应该是自治的,这可以通过将一个类与其依赖项隔离来实现.有几种方法可以做到这一点,这取决于您是否使用 IoC 注入依赖项(在Java 世界我们有 Spring、EJB3 和其他提供注入功能的框架/平台)和/或如果你模拟对象(对于 Java,你有 JMock 和 EasyMock) 将被测试的类与其依赖项分开.
A core rule for unit tests is that they should be autonomous, and that can be achieved by isolating a class from its dependencies. There are several ways to do it and it depends on if you inject your dependencies using IoC (in the Java world we have Spring, EJB3 and other frameworks/platforms which provide injection capabilities) and/or if you mock objects (for Java you have JMock and EasyMock) to separate a class being tested from its dependencies.
如果我们需要测试不同类中的方法组*并查看它们是否很好地集成,我们编写 集成测试.这是我的问题!
If we need to test groups of methods in different classes* and see that they are well integration, we write integration tests. And here is my question!
- 至少在 Web 应用程序中,状态通常保存在数据库中.我们可以使用与单元测试相同的工具来实现与数据库的独立性.但以我的拙见,我认为在某些情况下,不使用数据库进行集成测试是在嘲笑太多(但可以不同意;根本不使用数据库也是一个有效的答案,因为它使问题变得无关紧要).
- 当您使用数据库进行集成测试时,如何用数据填充该数据库?我可以看到两种方法:
- 存储集成测试的数据库内容并在开始测试之前加载它.如果它存储为 SQL 转储、数据库文件、XML 或其他内容,将会很有趣.
- 通过 API 调用创建必要的数据库结构.这些调用可能在您的测试代码中被拆分为多个方法,并且这些方法中的每一个可能失败.它可以被视为您的集成测试依赖于其他测试.
- At least in web applications, state is often persisted to a database. We could use the same tools as for unit tests to achieve independence from the database. But in my humble opinion I think that there are cases when not using a database for integration tests is mocking too much (but feel free to disagree; not using a database at all, ever, is also a valid answer as it makes the question irrelevant).
- When you use a database for integration tests, how do you fill that database with data? I can see two approaches:
- Store the database contents for the integration test and load it before starting the test. If it's stored as an SQL dump, a database file, XML or something else would be interesting to know.
- Create the necessary database structures by API calls. These calls are probably split up into several methods in your test code and each of these methods may fail. It could be seen as your integration test having dependencies on other tests.
您如何确定测试所需的数据库数据在您需要时是否存在?你为什么选择你选择的方法?
How are you making certain that database data needed for tests is there when you need it? And why did you choose the method you choose?
请提供带有动机的答案,因为有趣的部分在于动机.请记住,只是说这是最佳实践!"不是一个真正的动机,它只是重复你读过或从某人那里听到的东西.对于这种情况,请解释为什么这是最佳做法.
Please provide an answer with a motivation, as it's in the motivation the interesting part lies. Remember that just saying "It's best practice!" isn't a real motivation, it's just re-iterating something you've read or heard from someone. For that case please explain why it's best practice.
*在我的单元测试定义中,我在同一类的(相同或其他)实例中包含一个调用其他方法的方法,即使它在技术上可能不正确.请随时纠正我,但让我们把它作为一个附带问题.
*I'm including one method calling other methods in (the same or other) instances of the same class in my definition of unit test, even though it might technically not be correct. Feel free to correct me, but let's keep it as a side issue.
推荐答案
我更喜欢使用 API 调用创建测试数据.
I prefer creating the test data using API calls.
在测试开始时,您创建一个空数据库(内存中或生产中使用的相同),运行安装脚本对其进行初始化,然后创建数据库使用的任何测试数据.例如,可以使用 Object Mother 模式来组织测试数据的创建,以便相同的数据可以在许多测试中重复使用,可能会有细微的变化.
In the beginning of the test, you create an empty database (in-memory or the same that is used in production), run the install script to initialize it, and then create whatever test data used by the database. Creation of the test data may be organized for example with the Object Mother pattern, so that the same data can be reused in many tests, possibly with minor variations.
您希望在每次测试之前使数据库处于已知状态,以便进行可重现的测试而不会产生副作用.所以当一个测试结束时,你应该删除测试数据库或者回滚事务,这样下一个测试可以总是以同样的方式重新创建测试数据,不管之前的测试是通过还是失败.
You want to have the database in a known state before every test, in order to have reproducable tests without side effects. So when a test ends, you should drop the test database or roll back the transaction, so that the next test could recreate the test data always the same way, regardless of whether the previous tests passed or failed.
我会避免导入数据库转储(或类似的)的原因是它将测试数据与数据库模式耦合.当数据库架构发生变化时,您还需要更改或重新创建测试数据,这可能需要手动操作.
The reason why I would avoid importing database dumps (or similar), is that it will couple the test data with the database schema. When the database schema changes, you would also need to change or recreate the test data, which may require manual work.
如果测试数据是在代码中指定的,您将拥有 IDE 重构工具的强大功能.当您进行影响数据库架构的更改时,它可能还会影响 API 调用,因此您无论如何都需要使用 API 重构代码.通过几乎相同的努力,您还可以重构测试数据的创建 - 特别是如果重构可以自动化(重命名、引入参数等).但如果测试依赖于数据库转储,除了重构使用 API 的代码之外,您还需要手动重构数据库转储.
If the test data is specified in code, you will have the power of your IDE's refactoring tools at your hand. When you make a change which affects the database schema, it will probably also affect the API calls, so you will anyways need to refactor the code using the API. With nearly the same effort you can also refactor the creation of the test data - especially if the refactoring can be automated (renames, introducing parameters etc.). But if the tests rely on a database dump, you would need to manually refactor the database dump in addition to refactoring the code which uses the API.
与集成测试数据库相关的另一件事是测试从以前的数据库模式升级是否正常工作.为此,您可能需要阅读 Refactoring Databases: Evolutionary Database Design 一书 或这篇文章:http://martinfowler.com/articles/evodb.html
Another thing related to integration testing the database, is testing that upgrading from a previous database schema works right. For that you might want to read the book Refactoring Databases: Evolutionary Database Design or this article: http://martinfowler.com/articles/evodb.html
这篇关于集成测试所需的数据库数据;由 API 调用或使用导入的数据创建?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!