我是单元测试的新手。我有这些类AccountBl,它们调用使用SqlConnection的DataStore来从数据库中获取数据。
我需要通过模拟数据源来测试AccountBl.GetInvestmentAccounts方法,即使没有数据库连接也需要运行测试。
这是给定的类AccountBl:
public class AccountBl
{
private readonly DataStore dataStore = new DataStore();
public List<Account> GetInvestmentAccounts(int clientId, AccountType accountType)
{
if (accountType == AccountType.Investment)
{
var accounts = dataStore.LoadAccounts(clientId);
return accounts.Where(a => a.AccountType == AccountType.Investment).ToList();
}
throw new Exception("Invalid account type provided");
}
}
和数据存储:
public class DataStore
{
public static string GetAccountsSql = "irrelevant query";
public virtual List<Account> LoadAccounts(int clientId)
{
using (var connection = CreateConnection())
{
var sqlCommand = connection.CreateCommand();
sqlCommand.CommandText = GetAccountsSql;
sqlCommand.CommandType = CommandType.Text;
sqlCommand.Parameters.Add("@clientId", clientId);
var reader = sqlCommand.ExecuteReader();
var accounts = new List<Account>();
while (reader.Read())
{
var account = new Account();
account.AccountNumber = (string)reader["number"];
account.AccountOwner = clientId;
if (reader["accountType"] == null || reader["accountType"] == DBNull.Value)
{
account.AccountType = AccountType.Checking;
}
else
{
account.AccountType =
(AccountType)Enum.Parse(typeof(AccountType), reader["accountType"].ToString());
}
accounts.Add(account);
}
return accounts;
}
}
private static SqlConnection CreateConnection()
{
var sqlConnection = new SqlConnection(ConfigurationManager.AppSettings["ConnectionString"]);
sqlConnection.Open();
return sqlConnection;
}
}
这是我的TestClass
[TestClass]
public class UnitTest1
{
[TestMethod]
public void GetInvestmentAccountsTest()
{
var clientId = 25;
var mockAccounts = new List<Account>
{
new Account{AccountNumber = "aaa", AccountOwner = clientId, AccountType = AccountType.Investment},
new Account{AccountNumber = "bbb", AccountOwner = clientId, AccountType = AccountType.Savings},
new Account{AccountNumber = "ccc", AccountOwner = clientId, AccountType = AccountType.Checking},
};
var mockDatastore = new Mock<DataStore>();
mockDatastore.Setup(x => x.LoadAccounts(clientId)).Returns(mockAccounts);
var accountBl = new AccountBl();
var accounts = accountBl.GetInvestmentAccounts(clientId, AccountType.Investment);
}
}
运行时,我收到错误消息
消息:测试方法ScreeningSample.Tests.UnitTest1.GetInvestmentAccountsTest引发了异常:System.InvalidOperationException:ConnectionString属性尚未初始化。
显然,它试图创建一个连接,但是我需要在没有连接的情况下运行测试。
我在嘲笑吗?
所述readonly DataStore dataStore
待测对象被紧密地结合到类,使得难以隔离测试的主题。您将需要能够在测试期间替换该依赖性,以便能够进行独立测试。
考虑首先抽象化数据存储,
public interface IDataStore {
List<Account> LoadAccounts(int clientId);
}
并且让主题明确地通过构造函数注入依赖于该抽象,因为类应该依赖于抽象而不是依赖于具体概念。
public class AccountBl {
private readonly IDataStore dataStore;
public AccountBl(IDataStore dataStore) {
this.dataStore = dataStore;
}
public List<Account> GetInvestmentAccounts(int clientId, AccountType accountType) {
if (accountType == AccountType.Investment) {
var accounts = dataStore.LoadAccounts(clientId);
return accounts.Where(a => a.AccountType == AccountType.Investment).ToList();
}
throw new Exception("Invalid account type provided");
}
}
SqlConnection
是不再需要关注的实现细节 AccountBl
该DataStore
实现将从抽象派生。
public class DataStore : IDataStore {
public List<Account> LoadAccounts(int clientId) {
//...code removed for brevity
}
//...
}
现在,代码已解耦,可以更灵活地进行隔离测试了
[TestClass]
public class UnitTest1 {
[TestMethod]
public void GetInvestmentAccountsTest() {
//Arrange
var clientId = 25;
var mockAccounts = new List<Account> {
new Account{AccountNumber = "aaa", AccountOwner = clientId, AccountType = AccountType.Investment},
new Account{AccountNumber = "bbb", AccountOwner = clientId, AccountType = AccountType.Savings},
new Account{AccountNumber = "ccc", AccountOwner = clientId, AccountType = AccountType.Checking},
};
var mockDatastore = new Mock<IDataStore>();
mockDatastore.Setup(_ => _.LoadAccounts(clientId)).Returns(mockAccounts);
var subject = new AccountBl(mockDatastore.Object);
//Act
var accounts = subject.GetInvestmentAccounts(clientId, AccountType.Investment);
//Assert
//...
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句