你如何测试你的业务对象?

时间:2022-09-25 12:36:43

I am wanting to implement automated testing, using the Microsoft testing framework in Visual Studio, for my software development projects. I have created some tests, and all in all, it's pretty easy to use.

我想在我的软件开发项目中使用Visual Studio中的Microsoft测试框架实现自动化测试。我已经创建了一些测试,总而言之,它非常易于使用。

What are some better practices for testing business objects, more specifically ones that read and write to a database.

测试业务对象有哪些更好的实践,更具体地说是读取和写入数据库的实践。

Is it best to setup a separate test database, from the development database, where the user interface is tested from, and just test against that database? Basically just filling it with junk data.

是否最好从开发数据库中设置一个单独的测试数据库,从中测试用户界面,然后只测试该数据库?基本上只是填充垃圾数据。

Is it better to embrace some type of clean-up after yourself mentality, meaning, if I am testing the AddUser method, do I add the User, check my tests, and then delete the User?

是否更好地接受某种类型的清理后自己的心态,这意味着,如果我正在测试AddUser方法,我是否添加用户,检查我的测试,然后删除用户?

Do you test each of the CRUD methods in a single test method?

您是否在单一测试方法中测试每种CRUD方法?

Lastly, what about the individual business rules like verifying strings are of the correct size, start dates are less than end dates, the CustomerId is a correct Customer and so on.

最后,如验证字符串的各个业务规则的大小是正确的,开始日期是否小于结束日期,CustomerId是正确的客户等等。

I realize this is a pretty broad question ... just looking for some direction ... taking baby steps.

我意识到这是一个非常广泛的问题......只是寻找一些方向......采取婴儿步骤。

More information...

Lot's of good answers! I'm not sure I would be able to pull off a mock database. I am using CSLA as the framework for my objects. It would take some serious refactoring to make this testable with mock objects. I'm going to look into this. Though, at some point, I do want to test the database interaction ... when using a mock database, where/when would you actually test the database communication?

很多很好的答案!我不确定我是否能够启动模拟数据库。我使用CSLA作为我的对象的框架。需要一些严肃的重构才能使用mock对象进行测试。我要调查一下这个。虽然,在某些时候,我确实想测试数据库交互...当使用模拟数据库时,您何时/何时实际测试数据库通信?

One other question ... is it best to keep each test method non-dependent on other tests?

另一个问题......最好是保持每种测试方法不依赖于其他测试吗?

8 个解决方案

#1


Ideally, you would have business objects that do not directly access the database, but use helper objects or some kind of ORM (Object-relational mapping) framework. Then you can test your BOs without a database, possibly mocking some helper objects. That is probably the cleanest way, because you avoid the complexity of a real DB, and really only test your business logic.

理想情况下,您将拥有不直接访问数据库的业务对象,但使用帮助程序对象或某种ORM(对象关系映射)框架。然后你可以在没有数据库的情况下测试你的BO,可能会模拟一些帮助对象。这可能是最干净的方式,因为您避免了真正的数据库的复杂性,并且实际上只测试您的业务逻辑。

If you cannot avoid combining business rules and DB access into one class (probably a problematic design, but sometimes hard to avoid), then you have to test against a DB.

如果您无法避免将业务规则和数据库访问组合到一个类中(可能是有问题的设计,但有时难以避免),那么您必须针对数据库进行测试。

There pretty much the only reasonable option is to have a separate DB for automatic testing. Your test methods should delete everything on setup on setup, then load all their data, do the test and verify results.

几乎唯一合理的选择是有一个单独的DB进行自动测试。您的测试方法应删除设置时的所有设置,然后加载所有数据,进行测试并验证结果。

Don't even think about trying initialise the DB once and then run all tests on the same data. One test will accidentally change data, and other tests will mysteriously fail. I've done that and regretted it... Each test really must stand on its own.

甚至不要考虑尝试初始化DB一次,然后对相同的数据运行所有测试。一次测试会意外地改变数据,其他测试将神秘地失败。我已经做到了并后悔...每个测试都必须独立存在。

To do all this, I strongly recommend some kind of DB testing framework. These help you to clean the DB, load necessary data, and compare query results to expected results. I use DBUnit (for Java), but there are many others for other languages.

为了做到这一切,我强烈推荐某种数据库测试框架。这些可帮助您清理数据库,加载必要的数据,并将查询结果与预期结果进行比较。我使用DBUnit(用于Java),但还有许多其他语言。

#2


I would recommend implementing your business objects so that they are unaware of the database. Use methods on the data access layer that can save/retrieve business objects properly depending on their type (i.e., it has an internal mapping between the tables and the objects they correspond to). When testing your business object itself, then you need not worry about the database at all. Simply create the object, perhaps use reflection to set private fields, and conduct your test on the object.

我建议实现您的业务对象,以便他们不知道数据库。在数据访问层上使用可以根据类型正确保存/检索业务对象的方法(即,它具有表与它们对应的对象之间的内部映射)。在测试业务对象本身时,您根本不必担心数据库。只需创建对象,可能使用反射来设置私有字段,并对对象进行测试。

When testing code that needs to interact with the data access layer, use mocking to create a mock data layer and set up expectations on it to return the desired objects or respond properly to saves. You may need to develop your data layer to an interface (or wrap it with a mockable class if using a rigid framework that doesn't support mocking directly). Most mocking frameworks require that methods be virtual to allow a mock implementation to be created. Using interfaces forces the methods in the implementing class to be virtual so mocking is much easier.

在测试需要与数据访问层交互的代码时,使用模拟来创建模拟数据层并对其设置期望以返回所需对象或正确响应保存。您可能需要将数据层开发为接口(或者如果使用不直接支持模拟的刚性框架,则将其与可模拟类包装在一起)。大多数模拟框架都要求方法是虚拟的,以允许创建模拟实现。使用接口强制实现类中的方法是虚拟的,因此模拟更容易。

#3


Use dependency injection. Implement your database methods in an interface. Then write a new implementation of the interface with control data to test the applicable scenarios.

使用依赖注入。在接口中实现数据库方法。然后使用控制数据编写接口的新实现,以测试适用的方案。

#4


More info about TDD with CSLA can be found in the answers to this question. Especially this one.

有关TDD with CSLA的更多信息,请参阅此问题的答案。特别是这个。

Also this question might be interesting.

这个问题也许很有趣。

#5


Generally I create the BO, save it to the db in the fixture setup, then have tests for various insert/update/selects then in my teardown delete the object from the database. It keeps things nice and clean especially when lots of constraints are involved, your test db can get messy real quick if you don't remove everything you create in your tests.

通常我创建BO,将其保存到夹具设置中的db,然后测试各种插入/更新/选择然后在我的拆卸中从数据库中删除对象。它使事情保持良好和干净,特别是当涉及到许多约束时,如果不删除在测试中创建的所有内容,则测试数据库可能会非常快速。

#6


To test DB Access Layer, you should not run all tests on same db. Some tests may fail because they depend on the results of other test. So this is not what you want. Actually after every test, you should return the db status to the original status before the test runs.

要测试数据库访问层,不应在同一个数据库上运行所有测试。某些测试可能会失败,因为它们取决于其他测试的结果。所以这不是你想要的。实际上,在每次测试之后,您应该在测试运行之前将db状态返回到原始状态。

In my practice, I keep the test data set in a XML and before every test, it setup the data in db using the XML. So every test runs against some dataset.

在我的实践中,我将测试数据集保存在XML中,在每次测试之前,它使用XML在db中设置数据。因此,每个测试都针对某些数据集运行。

#7


I support the once saying that you should test you business objects with a moched database. In some cases you might want to have your data persisted as part of the test though. The drawbacks to this are longer running tests and the need for cleanup.

我支持曾经说过你应该使用moched数据库测试业务对象。在某些情况下,您可能希望将数据作为测试的一部分保留。缺点是运行时间更长,需要清理。

One solution to this that might help you is to use an in-memory database for your tests. SQLite for instance lets you create in-memory databases on the fly, and when you dispose them they are gone. This makes your tests much faster, and you don't have to set up cleanup code - while you actually get to test your SQL / db code through automated tests.

一个可能对您有帮助的解决方案是使用内存数据库进行测试。例如,SQLite允许您动态创建内存数据库,当您处置它们时它们就消失了。这使您的测试更快,并且您不必设置清理代码 - 而您实际上是通过自动化测试来测试您的SQL / db代码。

#8


(I know you don´t use Java but the general strategy below does not depend on Java at all)

(我知道你不使用Java,但下面的一般策略根本不依赖于Java)

I'm working on a Java project that uses a lot of EJB3/JPA code. I decided to create a kind of mock container able to "deploy" EJBs and use an in-memory database (HSQL) with hibernate entity manager.

我正在研究一个使用大量EJB3 / JPA代码的Java项目。我决定创建一种能够“部署”EJB并使用内存数据库(HSQL)和hibernate实体管理器的模拟容器。

This "container" starts up in less than 1 second and allows me to test most business components, including those that access the database via JPA. If a service is, for example, too complex to support then I simply use EasyMock (or any other mock library) to create a fake service and plug in into the "container".

这个“容器”在不到1秒的时间内启动,允许我测试大多数业务组件,包括那些通过JPA访问数据库的组件。例如,如果服务太复杂而无法支持,那么我只需使用EasyMock(或任何其他模拟库)来创建虚假服务并插入“容器”。

It's been a huge success so far, but required me a couple of days to implement the mock infrastructure.

到目前为止,这是一个巨大的成功,但需要我几天时间来实现模拟基础架构。

#1


Ideally, you would have business objects that do not directly access the database, but use helper objects or some kind of ORM (Object-relational mapping) framework. Then you can test your BOs without a database, possibly mocking some helper objects. That is probably the cleanest way, because you avoid the complexity of a real DB, and really only test your business logic.

理想情况下,您将拥有不直接访问数据库的业务对象,但使用帮助程序对象或某种ORM(对象关系映射)框架。然后你可以在没有数据库的情况下测试你的BO,可能会模拟一些帮助对象。这可能是最干净的方式,因为您避免了真正的数据库的复杂性,并且实际上只测试您的业务逻辑。

If you cannot avoid combining business rules and DB access into one class (probably a problematic design, but sometimes hard to avoid), then you have to test against a DB.

如果您无法避免将业务规则和数据库访问组合到一个类中(可能是有问题的设计,但有时难以避免),那么您必须针对数据库进行测试。

There pretty much the only reasonable option is to have a separate DB for automatic testing. Your test methods should delete everything on setup on setup, then load all their data, do the test and verify results.

几乎唯一合理的选择是有一个单独的DB进行自动测试。您的测试方法应删除设置时的所有设置,然后加载所有数据,进行测试并验证结果。

Don't even think about trying initialise the DB once and then run all tests on the same data. One test will accidentally change data, and other tests will mysteriously fail. I've done that and regretted it... Each test really must stand on its own.

甚至不要考虑尝试初始化DB一次,然后对相同的数据运行所有测试。一次测试会意外地改变数据,其他测试将神秘地失败。我已经做到了并后悔...每个测试都必须独立存在。

To do all this, I strongly recommend some kind of DB testing framework. These help you to clean the DB, load necessary data, and compare query results to expected results. I use DBUnit (for Java), but there are many others for other languages.

为了做到这一切,我强烈推荐某种数据库测试框架。这些可帮助您清理数据库,加载必要的数据,并将查询结果与预期结果进行比较。我使用DBUnit(用于Java),但还有许多其他语言。

#2


I would recommend implementing your business objects so that they are unaware of the database. Use methods on the data access layer that can save/retrieve business objects properly depending on their type (i.e., it has an internal mapping between the tables and the objects they correspond to). When testing your business object itself, then you need not worry about the database at all. Simply create the object, perhaps use reflection to set private fields, and conduct your test on the object.

我建议实现您的业务对象,以便他们不知道数据库。在数据访问层上使用可以根据类型正确保存/检索业务对象的方法(即,它具有表与它们对应的对象之间的内部映射)。在测试业务对象本身时,您根本不必担心数据库。只需创建对象,可能使用反射来设置私有字段,并对对象进行测试。

When testing code that needs to interact with the data access layer, use mocking to create a mock data layer and set up expectations on it to return the desired objects or respond properly to saves. You may need to develop your data layer to an interface (or wrap it with a mockable class if using a rigid framework that doesn't support mocking directly). Most mocking frameworks require that methods be virtual to allow a mock implementation to be created. Using interfaces forces the methods in the implementing class to be virtual so mocking is much easier.

在测试需要与数据访问层交互的代码时,使用模拟来创建模拟数据层并对其设置期望以返回所需对象或正确响应保存。您可能需要将数据层开发为接口(或者如果使用不直接支持模拟的刚性框架,则将其与可模拟类包装在一起)。大多数模拟框架都要求方法是虚拟的,以允许创建模拟实现。使用接口强制实现类中的方法是虚拟的,因此模拟更容易。

#3


Use dependency injection. Implement your database methods in an interface. Then write a new implementation of the interface with control data to test the applicable scenarios.

使用依赖注入。在接口中实现数据库方法。然后使用控制数据编写接口的新实现,以测试适用的方案。

#4


More info about TDD with CSLA can be found in the answers to this question. Especially this one.

有关TDD with CSLA的更多信息,请参阅此问题的答案。特别是这个。

Also this question might be interesting.

这个问题也许很有趣。

#5


Generally I create the BO, save it to the db in the fixture setup, then have tests for various insert/update/selects then in my teardown delete the object from the database. It keeps things nice and clean especially when lots of constraints are involved, your test db can get messy real quick if you don't remove everything you create in your tests.

通常我创建BO,将其保存到夹具设置中的db,然后测试各种插入/更新/选择然后在我的拆卸中从数据库中删除对象。它使事情保持良好和干净,特别是当涉及到许多约束时,如果不删除在测试中创建的所有内容,则测试数据库可能会非常快速。

#6


To test DB Access Layer, you should not run all tests on same db. Some tests may fail because they depend on the results of other test. So this is not what you want. Actually after every test, you should return the db status to the original status before the test runs.

要测试数据库访问层,不应在同一个数据库上运行所有测试。某些测试可能会失败,因为它们取决于其他测试的结果。所以这不是你想要的。实际上,在每次测试之后,您应该在测试运行之前将db状态返回到原始状态。

In my practice, I keep the test data set in a XML and before every test, it setup the data in db using the XML. So every test runs against some dataset.

在我的实践中,我将测试数据集保存在XML中,在每次测试之前,它使用XML在db中设置数据。因此,每个测试都针对某些数据集运行。

#7


I support the once saying that you should test you business objects with a moched database. In some cases you might want to have your data persisted as part of the test though. The drawbacks to this are longer running tests and the need for cleanup.

我支持曾经说过你应该使用moched数据库测试业务对象。在某些情况下,您可能希望将数据作为测试的一部分保留。缺点是运行时间更长,需要清理。

One solution to this that might help you is to use an in-memory database for your tests. SQLite for instance lets you create in-memory databases on the fly, and when you dispose them they are gone. This makes your tests much faster, and you don't have to set up cleanup code - while you actually get to test your SQL / db code through automated tests.

一个可能对您有帮助的解决方案是使用内存数据库进行测试。例如,SQLite允许您动态创建内存数据库,当您处置它们时它们就消失了。这使您的测试更快,并且您不必设置清理代码 - 而您实际上是通过自动化测试来测试您的SQL / db代码。

#8


(I know you don´t use Java but the general strategy below does not depend on Java at all)

(我知道你不使用Java,但下面的一般策略根本不依赖于Java)

I'm working on a Java project that uses a lot of EJB3/JPA code. I decided to create a kind of mock container able to "deploy" EJBs and use an in-memory database (HSQL) with hibernate entity manager.

我正在研究一个使用大量EJB3 / JPA代码的Java项目。我决定创建一种能够“部署”EJB并使用内存数据库(HSQL)和hibernate实体管理器的模拟容器。

This "container" starts up in less than 1 second and allows me to test most business components, including those that access the database via JPA. If a service is, for example, too complex to support then I simply use EasyMock (or any other mock library) to create a fake service and plug in into the "container".

这个“容器”在不到1秒的时间内启动,允许我测试大多数业务组件,包括那些通过JPA访问数据库的组件。例如,如果服务太复杂而无法支持,那么我只需使用EasyMock(或任何其他模拟库)来创建虚假服务并插入“容器”。

It's been a huge success so far, but required me a couple of days to implement the mock infrastructure.

到目前为止,这是一个巨大的成功,但需要我几天时间来实现模拟基础架构。