Jam*_*ers 12 c# unit-testing mocking isolation-frameworks
我正在努力学习如何进行单元测试和模拟.我理解TDD和基本测试的一些原理.但是,我正在考虑重构下面的代码,这些代码是在没有测试的情况下编写的,并且我试图了解它是如何更改以使其可测试的.
public class AgentRepository
{
public Agent Select(int agentId)
{
Agent tmp = null;
using (IDataReader agentInformation = GetAgentFromDatabase(agentId))
{
if (agentInformation.Read())
{
tmp = new Agent();
tmp.AgentId = int.Parse(agentInformation["AgentId"].ToString());
tmp.FirstName = agentInformation["FirstName"].ToString();
tmp.LastName = agentInformation["LastName"].ToString();
tmp.Address1 = agentInformation["Address1"].ToString();
tmp.Address2 = agentInformation["Address2"].ToString();
tmp.City = agentInformation["City"].ToString();
tmp.State = agentInformation["State"].ToString();
tmp.PostalCode = agentInformation["PostalCode"].ToString();
tmp.PhoneNumber = agentInformation["PhoneNumber"].ToString();
}
}
return tmp;
}
private IDataReader GetAgentFromDatabase(int agentId)
{
SqlCommand cmd = new SqlCommand("SelectAgentById");
cmd.CommandType = CommandType.StoredProcedure;
SqlDatabase sqlDb = new SqlDatabase("MyConnectionString");
sqlDb.AddInParameter(cmd, "AgentId", DbType.Int32, agentId);
return sqlDb.ExecuteReader(cmd);
}
}
Run Code Online (Sandbox Code Playgroud)
这两种方法属于单一类.GetAgentFromDatabase中与数据库相关的代码与Enterprise Libraries相关.
我怎样才能使这个可测试?我应该将GetAgentFromDatabase方法抽象为另一个类吗?GetAgentFromDatabase应该返回除IDataReader之外的其他内容吗?任何建议或指向外部链接将不胜感激.
将GetAgentFromDatabase()移动到单独的类中是正确的.以下是我重新定义AgentRepository的方法:
public class AgentRepository {
private IAgentDataProvider m_provider;
public AgentRepository( IAgentDataProvider provider ) {
m_provider = provider;
}
public Agent GetAgent( int agentId ) {
Agent agent = null;
using( IDataReader agentDataReader = m_provider.GetAgent( agentId ) ) {
if( agentDataReader.Read() ) {
agent = new Agent();
// set agent properties later
}
}
return agent;
}
}
Run Code Online (Sandbox Code Playgroud)
我在哪里定义了IAgentDataProvider接口,如下所示:
public interface IAgentDataProvider {
IDataReader GetAgent( int agentId );
}
Run Code Online (Sandbox Code Playgroud)
因此,AgentRepository是被测试的类.我们将模拟IAgentDataProvider并注入依赖项.(我是用Moq做的,但您可以使用不同的隔离框架轻松地重做它).
[TestFixture]
public class AgentRepositoryTest {
private AgentRepository m_repo;
private Mock<IAgentDataProvider> m_mockProvider;
[SetUp]
public void CaseSetup() {
m_mockProvider = new Mock<IAgentDataProvider>();
m_repo = new AgentRepository( m_mockProvider.Object );
}
[TearDown]
public void CaseTeardown() {
m_mockProvider.Verify();
}
[Test]
public void AgentFactory_OnEmptyDataReader_ShouldReturnNull() {
m_mockProvider
.Setup( p => p.GetAgent( It.IsAny<int>() ) )
.Returns<int>( id => GetEmptyAgentDataReader() );
Agent agent = m_repo.GetAgent( 1 );
Assert.IsNull( agent );
}
[Test]
public void AgentFactory_OnNonemptyDataReader_ShouldReturnAgent_WithFieldsPopulated() {
m_mockProvider
.Setup( p => p.GetAgent( It.IsAny<int>() ) )
.Returns<int>( id => GetSampleNonEmptyAgentDataReader() );
Agent agent = m_repo.GetAgent( 1 );
Assert.IsNotNull( agent );
// verify more agent properties later
}
private IDataReader GetEmptyAgentDataReader() {
return new FakeAgentDataReader() { ... };
}
private IDataReader GetSampleNonEmptyAgentDataReader() {
return new FakeAgentDataReader() { ... };
}
}
Run Code Online (Sandbox Code Playgroud)
(我省略了类FakeAgentDataReader的实现,它实现了IDataReader并且很简单 - 你只需要实现Read()和Dispose()来使测试工作.)
这里AgentRepository的目的是获取IDataReader对象并将它们转换为正确形成的Agent对象.您可以扩展上述测试夹具以测试更有趣的案例.
在将AgentRepository与实际数据库隔离开来进行单元测试后,您将需要对IAgentDataProvider的具体实现进行单元测试,但这是一个单独问题的主题.HTH
| 归档时间: |
|
| 查看次数: |
578 次 |
| 最近记录: |