如何用数据库查询单元测试对象 [英] How to unit test an object with database queries
问题描述
我使用PHP和Python,但我认为这是一个问题,适用于大多数/所有语言使用数据库访问。
我建议嘲笑你的数据库调用。 Mocks基本上是对象,看起来像你试图调用一个方法的对象,在它们具有相同的属性,方法等可用于调用者的意义上。但是,当调用特定方法时,它不是执行它们被编程的任何动作,而是完全跳过,并且返回结果。这个结果通常由你提前定义。
为了设置你的对象进行嘲笑,你可能需要使用某种反转的控制/依赖注入模式,如下面的伪代码: / p>
class Bar
{
private FooDataProvider _dataProvider;
public instantiate(FooDataProvider dataProvider){
_dataProvider = dataProvider;
}
public getAllFoos(){
//而不是调用Foo.GetAll()在这里,我们引入一个额外的抽象层
return _dataProvider.GetAllFoos ();
}
}
class FooDataProvider
{
public Foo [] GetAllFoos(){
return Foo.GetAll
}
}
现在在你的单元测试中,你创建一个模拟FooDataProvider,它允许你调用方法GetAllFoos而不必实际命中数据库。
class BarTests
{
public TestGetAllFoos(){
//这里我们设置我们的mock FooDataProvider
mockRepository = MockingFramework.new()
mockFooDataProvider = mockRepository.CreateMockOfType(FooDataProvider);
//创建一个新的Foo对象数组
testFooArray = new Foo [] {Foo.new(),Foo.new(),Foo.new()}
//下一条语句将导致每当我们调用FooDAtaProvider.GetAllFoos,
//时返回testFooArray,而不是调用数据库并返回任何内容
// ExpectCallTo和Returns是我们假想的模拟框架提供的方法
ExpectCallTo(mockFooDataProvider.GetAllFoos).Returns(testFooArray)
//现在开始我们的实际单元测试
testBar = new Bar(mockFooDataProvider)
baz = testBar.GetAllFoos()
// baz现在应该等于我们之前创建的testFooArray对象
Assert.AreEqual(3,baz.length)
}
}
一个常见的嘲笑场景。当然,你仍然可能想要单元测试你的实际数据库调用,你需要打到数据库。
I've heard that unit testing is "totally awesome", "really cool" and "all manner of good things" but 70% or more of my files involve database access (some read and some write) and I'm not sure how to write a unit test for these files.
I'm using PHP and Python but I think it's a question that applies to most/all languages that use database access.
I would suggest mocking out your calls to the database. Mocks are basically objects that look like the object you are trying to call a method on, in the sense that they have the same properties, methods, etc. available to caller. But instead of performing whatever action they are programmed to do when a particular method is called, it skips that altogether, and just returns a result. That result is typically defined by you ahead of time.
In order to set up your objects for mocking, you probably need to use some sort of inversion of control/ dependency injection pattern, as in the following pseudo-code:
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();
}
}
Now in your unit test, you create a mock of FooDataProvider, which allows you to call the method GetAllFoos without having to actually hit the database.
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)
}
}
A common mocking scenario, in a nutshell. Of course you will still probably want to unit test your actual database calls too, for which you will need to hit the database.
这篇关于如何用数据库查询单元测试对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!