我对单元测试很陌生,我需要一只手来理解我是否正在以正确的方式做事。我的主要问题是关于数据库测试...这是我的代码,然后我将暴露我的困惑
考虑这个类,它是我要执行的管道项目
public class RetrieveApplicationUsernamePipelineStep : IPipelineStep
{
public const string RetrieveApplicationUsernameKey = "RetrieveApplicationUsername";
private readonly IRetrieveApplicationUserRepository repository;
public int Order => 3;
public string Name => RetrieveApplicationUsernameKey;
public RetrieveApplicationUsernamePipelineStep(IRetrieveApplicationUserRepository repository)
{
this.repository = repository;
}
public async Task<IDictionary<string, object>> Action(IDictionary<string, object> context)
{
string res = await repository.GetApplicationUser(context);
context[Resources.ApplicationUser] = res;
return context;
}
}
我写了以下测试
[TestFixture]
public class RetrieveApplicationUsernamePipelineStepTests
{
private IRetrieveApplicationUserRepository retrieveApplicationUserRepository;
[OneTimeSetUp]
public void Start()
{
var configuration = new ConfigurationFromConfigFile();
retrieveApplicationUserRepository = new RetrieveApplicationUserRepository(configuration);
}
[Test]
public async Task ActionSuccessfullyCompleted()
{
var context = new Dictionary<string, object>();
var repository = Substitute.For<IRetrieveApplicationUserRepository>();
repository.GetApplicationUser(context).Returns("user1");
var pipeline = new RetrieveApplicationUsernamePipelineStep(repository);
var res = await pipeline.Action(context);
Assert.IsNotNull(res[Resources.ApplicationUser]);
Assert.IsNotEmpty((string)res[Resources.ApplicationUser]);
}
[Test]
public void ActionFailingCompleted()
{
var context = new Dictionary<string, object>();
var repository = Substitute.For<IRetrieveApplicationUserRepository>();
repository.GetApplicationUser(context).Throws(new UserMappingNotFoundException());
var pipeline = new RetrieveApplicationUsernamePipelineStep(repository);
Assert.ThrowsAsync<UserMappingNotFoundException>(async () => await pipeline.Action(context));
}
[Test]
public void NameTest()
{
var pipeline = new RetrieveApplicationUsernamePipelineStep(retrieveApplicationUserRepository);
Assert.IsTrue(pipeline.Name == RetrieveApplicationUsernamePipelineStep.RetrieveApplicationUsernameKey);
}
[Test]
public void OrderTest()
{
var pipeline = new RetrieveApplicationUsernamePipelineStep(retrieveApplicationUserRepository);
Assert.IsTrue(pipeline.Order == 3);
}
}
这些测试工作正常,因为对于ActionSuccessfullyCompleted和ActionFailingCompleted,我将IRetrieveApplicationUserRepository的结果替换为我期望的结果。
存储库的真正实现是
public class RetrieveApplicationUserRepository : IRetrieveApplicationUserRepository
{
#region Variables
private readonly IConfiguration configuration;
#endregion
#region Ctor
public RetrieveApplicationUserRepository(IConfiguration configuration)
{
this.configuration = configuration;
}
#endregion
#region IRetrieveApplicationUserRepository
public async Task<string> GetApplicationUser(IDictionary<string, object> context)
{
if (configuration.AppSettings[Resources.ApplicationUserFromDomainUserKey] == null)
throw new KeyNotFoundException(Resources.ApplicationUserFromDomainUserKey);
if (string.IsNullOrEmpty(configuration.ConnectionString))
throw new NullReferenceException();
string storedProcedure = configuration.AppSettings.Get(Resources.ApplicationUserFromDomainUserKey);
string result;
using (var sqlConnection = new SqlConnection(configuration.ConnectionString))
{
using (var sqlCommand = new SqlCommand(storedProcedure, sqlConnection))
{
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.Parameters.AddWithValue("@DOMAINUSER", context[Resources.DomainUser]);
sqlCommand.Parameters.AddWithValue("@DOMAIN", context[Resources.DomainName]);
sqlCommand.Parameters.AddWithValue("@APPID", context[Resources.ApplicationId]);
sqlConnection.Open();
result = (string)await sqlCommand.ExecuteScalarAsync();
}
}
if (result == null)
throw new UserMappingNotFoundException();
return result;
}
#endregion
}
以下是问题:
答案 0 :(得分:1)
通常的方法是使用抽象来隔离数据库端,因此您可以提供该抽象的测试虚拟(模拟,伪造等)。仅在执行集成测试时测试实际数据库。
对于数据库存储过程的测试,您可能需要一个不同的测试工具,在内存中创建一个新的测试数据库(相当于在RAM支持的文件系统中)。您只需要为单个测试填充足够的数据(我们在这里进行功能测试,而不是性能测试),并且您可以通过合理使用回滚来保留测试中的表结构。
我已经这样做了,但是不久之前,所以我将不再提供可能不再是最新技术的示例(即使代码仍然存在,如果我能找到它)