我有一份工作,我有一个IDisposable DbContext。我想在没有进入数据库的情况下对这项工作进行单元测试。我有什么选择呢?
我正在使用微软的默认Fakes程序集。
我的工作:
public void Work()
{
do
{
//code here
using (var repository = new Repository<User>())
{
repository.Save(user);
}
} while (true);
}
我正在尝试测试并且在测试的这一部分中它失败了,因为它实际上创建了一个Repository类的新实例。
我的测试方法:
using (ShimsContext.Create())
{
Data.Repository.Fakes.ShimRepository<Domain.Fakes.ShimUser>.Constructor = (a) => { };
Data.Repository.Fakes.ShimRepository<Domain.Fakes.ShimUser>.AllInstances.SaveT0 = (a, b) =>
{
};
var service = GetService();
service.Work(); //Throws exception
}
如何伪造此Save
方法?
答案 0 :(得分:7)
您在这里违反了DIP,使得对您的服务进行单元测试的难度远远超过应有的水平。您还应该避免使用通用存储库并支持role interfaces。
相反,请将抽象注入您的存储库服务,例如: IUsersRepository
定义了您的Save
方法。然后在服务的单元测试中,您只需使用IUsersRepository
的存根实现。
答案 1 :(得分:2)
Fakes倾向于揭示您的代码没有正确地遵循SOLID中的D,因为您在类中创建依赖项而不是传入它们。
更好的模式是创建一个ISaveRepository
接口,然后使用公开的Save()
方法实现IDisposable。然后,您应该将您的存储库实例注入您的类。这将允许您满足using语句测试,以及实现一个模拟,该模拟定义了一个没有命中数据库的.Save()
方法。
public class Test
{
private readonly ISaveRepository _userRepository;
public Test(ISaveRepository userRepository)
{
_userRepository = userRepository;
}
public void Work()
{
using (_userRepository)
{
var cont = true;
do
{
_userRepository.Save(new User());
cont = false;
} while (cont);
}
}
}
public interface ISaveRepository : IDisposable
{
void Save<T>(T model);
}
public class Repository<T> : ISaveRepository
{
public void Dispose() { }
public void Save<TT>(TT model) {}
}
public class User {}