我听说单元测试“非常棒”,“真的很酷”,“各种各样的好东西”,但我的文件中有70%或更多涉及数据库访问(一些是读的,一些是写的),我不确定如何为这些文件编写单元测试。
我正在使用PHP和Python,但我认为这是一个适用于大多数/所有使用数据库访问的语言的问题。
发布于 2008-08-27 18:30:47
我建议模拟你对数据库的调用。模拟基本上是看起来像你试图调用方法的对象的对象,从某种意义上说,它们具有相同的属性、方法等可供调用者使用。但是,当一个特定的方法被调用时,它不会执行它们被编程执行的任何操作,而是完全跳过这一步,只返回一个结果。这个结果通常是由你提前定义的。
为了将对象设置为模拟,您可能需要使用某种控制反转/依赖注入模式,如下面的伪代码所示:
class Bar
{
private FooDataProvider _dataProvider;
public instantiate(FooDataProvider dataProvider) {
_dataProvider = dataProvider;
}
public getAllFoos() {
// instead of calling Foo.GetAll() here, we are introducing an extra layer of abstraction
return _dataProvider.GetAllFoos();
}
}
class FooDataProvider
{
public Foo[] GetAllFoos() {
return Foo.GetAll();
}
}
现在,在您的单元测试中,您将创建一个FooDataProvider模拟,它允许您在不必实际访问数据库的情况下调用方法GetAllFoos。
class BarTests
{
public TestGetAllFoos() {
// here we set up our mock FooDataProvider
mockRepository = MockingFramework.new()
mockFooDataProvider = mockRepository.CreateMockOfType(FooDataProvider);
// create a new array of Foo objects
testFooArray = new Foo[] {Foo.new(), Foo.new(), Foo.new()}
// the next statement will cause testFooArray to be returned every time we call FooDAtaProvider.GetAllFoos,
// instead of calling to the database and returning whatever is in there
// ExpectCallTo and Returns are methods provided by our imaginary mocking framework
ExpectCallTo(mockFooDataProvider.GetAllFoos).Returns(testFooArray)
// now begins our actual unit test
testBar = new Bar(mockFooDataProvider)
baz = testBar.GetAllFoos()
// baz should now equal the testFooArray object we created earlier
Assert.AreEqual(3, baz.length)
}
}
简单地说,这是一种常见的模仿场景。当然,您可能仍然希望对实际的数据库调用进行单元测试,为此,您需要访问数据库。
发布于 2008-08-27 18:14:54
对具有数据库访问权限的对象进行单元测试的最简单方法是使用事务作用域。
例如:
[Test]
[ExpectedException(typeof(NotFoundException))]
public void DeleteAttendee() {
using(TransactionScope scope = new TransactionScope()) {
Attendee anAttendee = Attendee.Get(3);
anAttendee.Delete();
anAttendee.Save();
//Try reloading. Instance should have been deleted.
Attendee deletedAttendee = Attendee.Get(3);
}
}
这将恢复数据库的状态,基本上类似于事务回滚,因此您可以根据需要多次运行测试,而不会产生任何副作用。我们已经在大型项目中成功地使用了这种方法。我们的构建确实需要一点时间来运行(15分钟),但对于拥有1800个单元测试来说,这并不可怕。此外,如果构建时间是一个问题,您可以将构建过程更改为具有多个构建,一个用于构建src,另一个随后启动以处理单元测试、代码分析、打包等……
发布于 2008-08-27 17:49:28
如果您想要对您的类进行单元测试,您应该模拟数据库访问。毕竟,您不希望在单元测试中测试数据库。这将是一次集成测试。
将调用抽象出来,然后插入一个仅返回预期数据的mock。如果您的类除了执行查询之外并不能做更多的工作,那么测试它们可能就不值得了……
https://stackoverflow.com/questions/30710
复制相似问题