我是使用Mocks的新手。但它的主要目的是什么?我将首先使用Moq来测试我的应用程序(和NUnit)。
例如,我的代码可以执行以下操作:
我的网页代码背后:
public partial class MyWebpage
{
protected string GetTitle(string myVar)
{
return dataLayer.GetTitle(myVar);
}
}
我的数据访问层:
public class DataLayer
{
public string GetTitle(string myVar)
{
// Create the query we want
string query = "SELECT title FROM MyTable " +
"WHERE var = @myVar";
//ENTER PARAMETERS IN HERE
// Now return the result to the view
return this.dataProvider.ExecuteMySelectQuery(
dr =>
{
//DELEGATE DATA READER PASSED IN AND TITLE GETS RETURNED
},
query,
parameters);
}
}
我的数据提供者直接与数据库进行对话并进行交互:
public class DataProvider
{
public T ExecuteMySelectQuery<T>(Func<IDataReader, T> getMyResult, string selectQuery, Dictionary parameters)
{
//RUNS AND RETURNS THE QUERY
}
}
测试所有这些的最佳方法是什么?
答案 0 :(得分:3)
如果要单独测试图层,则需要为DataProvider和DataLayer类创建接口,以显示您想要模拟的方法。然后你可以使用一个模拟框架 - NSubstitute非常好,用于创建模拟的代码更少 - 模拟对依赖类的调用,让你测试该特定单元内的代码
public interface IDataProvider
{
T ExecuteMySelectQuery<T>(Func<IDataReader, T> getMyResult, string selectQuery, Dictionary parameters);
}
public interface IDataLayer
{
string GetTitle(string myVar);
}
public class DataLayer
{
private IDataProvider dataProvider;
public DataLayer(IDataProvider dataProvider)
{
this.dataProvider = dataProvider;
}
}
然后,在测试代码中,创建模拟而不是真实对象,并在实例化测试对象时将它们传递给构造函数。测试DataLayer:
[Test]
public void WhenRetievingTitleFromDataStore_ThenDataLayerReturnsTitle()
{
var title = "Title";
var dataProviderMock = new Mock<IDataProvider>(MockBehavior.Strict);
dataProviderMock.Setup(x => x.ExecuteMySelectQuery(<parameters>)).Returns(title);
var dataLayer = new DataLayer(dataProviderMock.Object);
Assert.That(dataLayer.GetTitle(It.IsAny<string>(), Is.EqualTo(title));
}
答案 1 :(得分:2)
唯一可能出错的是DB调用(查询或返回的结果是错误的数据类型)。这不能被嘲笑。您需要进行集成测试而不是单元测试。
通常,您只能模拟能够在代码中测试逻辑。您应该进行测试,以便数据映射器(this.dataProvider.ExecuteMySelectQuery
)按照定义工作。但那是相关代码的范围。
<强>更新强>
所以你得到了以下课程:
public class DataLayer
{
public string GetTitle(string myVar)
{
// Create the query we want
string query = "SELECT title FROM MyTable " +
"WHERE var = @myVar";
//ENTER PARAMETERS IN HERE
// Now return the result to the view
return this.dataProvider.ExecuteMySelectQuery(
dr =>
{
//DELEGATE DATA READER PASSED IN AND TITLE GETS RETURNED
},
query,
parameters);
}
}
public class DataProvider
{
public T ExecuteMySelectQuery<T>(Func<IDataReader, T> getMyResult, string selectQuery, Dictionary parameters)
{
//RUNS AND RETURNS THE QUERY
}
}
如果我们检查ExecuteMySelectQuery
,我们可以看到DataLayer
类依赖于数据库返回的类型,因为DataProvider
只是简化了查询的执行。可以说它是ADO.NET之上的插件。
这也意味着你永远不能保证DataLayer
在不涉及数据库的情况下返回所承诺的内容。例如,假设数据库中的table
有一个名为title
的列,但有人设法使用int
数据类型。
可能出错的事情是
在模拟的帮助下,这些错误都不能被检测到或测试。
另一方面,如果你在另一个班级使用DataLayer
分类,你当然可以嘲笑它。因为DataLayer
类本身就是一个完整的抽象。这意味着该类的调用者不必知道它下面的任何东西。因此,嘲弄完全没问题。