我正在研究 NoSQL 数据库并且对单元测试有疑问。对业务逻辑进行单元测试的合适方法是什么?如何模拟 NoSQL 数据库?
3 回答
您的业务逻辑不应直接接触数据库,而应通过数据库访问层。这使您可以模拟该中间层以进行单元测试。为此,您可以使用依赖注入和模拟。有一些框架可以帮助您完成这两件事,但您也可以手动完成。这是一个例子:
假设我们有一个 DAL:
public class DBDataProvider: IDataProvider
{
public string getData()
{
//SQL to get data from actual database.
}
}
如您所见,这实现了一个接口,用于为您的业务层提供数据。它可能看起来像这样:
public Interface IDataProvider
{
String getData();
}
您的业务层可能如下所示:
public BusinessClass
{
private IDataProvider dataProvider;
public BusinessClass()
{
dataProvider = new DBDataProvider();
}
public BusinessClass(IDataProvider provider)
{
dataProvider = provider;
}
public void doBusinessStuff()
{
dataProvider.getData();
//Do something with data.
}
}
因此,现在在您的生产代码中,您将使用默认构造函数创建业务类,这将自动使您的类与数据库连接。但是,请注意,我们可以使用我们指定的 IDataProvider 创建一个 BusinessClass。因此,您可以制作一个“假”数据提供者仅用于测试:
public class MockDataProvider: IDataProvider
{
public string getData()
{
//return some expected result that you can control, without doing a DB call.
}
}
现在在您的测试中,您可以创建一个新的 MockDataProvider,并将其传递给 BusinessClass 的构造函数。您的业务类现在将使用您的模拟数据提供程序,而不是真正的数据库。
在这里,我手工完成了所有操作,但它让您了解了它是如何工作的。在现实生活中,您可以使用模拟和依赖注入框架为您编写一堆代码。
就像你模拟任何依赖一样。编写一个漂亮、简洁的合约,从中可以抽象出实现细节,然后模拟该合约。通常这是通过将数据访问层用作合同来完成的。
在不深入了解实际实现细节的情况下,假设您在要测试的方法中有一个查询:(注意,我从 ravenDB 示例中复制了此代码,但我对 ravenDB 的了解为 0,因此它甚至可能无法编译)
public void SomeMethod()
{
var name = "Hello";
var motto = "World";
using (var docStore = new DocumentStore("localhost", 8080).Initialize())
using (var session = documentStore.OpenSession()){
session.Store(new Company { Name = name, Motto = motto });;
session.SaveChanges();
}
}
这将很难模拟/测试,因为它需要 8080 上 localhost 上的数据库。现在,如果您将此逻辑分离到另一个类中:
public class AwesomeDAL
public virtual void AddCompany(string name, string motto){
using (var docStore = new DocumentStore("localhost", 8080).Initialize())
using (var session = documentStore.OpenSession()){
session.Store(new Company { Name = name, Motto = motto });;
session.SaveChanges();
}
}
并允许注入依赖项(AwesomeDal):
public class ClassBeingTested
{
public AwesomeDal DAL { get; set; }
public ClassBeingTested() : this(new AwesomeDal()){}
public ClassBeingTested(AwesomeDal dal)
{
this.DAL = dal;
}
public void SomeMethod()
{
var name = "Hello";
var motto = "World";
this.DAL.AddCompany(name, motto);
}
}
您现在可以单独测试 BL 代码。或者你可以模拟数据库异常,或者任何你需要测试的东西,因为你的数据访问层是抽象的,并且它的实现很容易用像Moq或 RhinoMocks这样的框架来模拟
除了已经发布的(正确)答案之外,让我提出一个替代解决方案:使用真正的开发数据库!没有什么比真实的东西更真实的模拟了。如果您直接对其进行测试,至少您知道您的代码将实际运行。
如果您可以轻松地抽象出您的数据库,我建议您这样做。