C# 单元测试工作单元
单元测试的新手。我有一个工作单元,我正在尝试进行单元测试。我可能错过了一些简单的东西。我正在尝试对提交方法进行单元测试。我正在使用nunit和moqC# 单元测试工作单元,c#,unit-testing,nunit,moq,C#,Unit Testing,Nunit,Moq,单元测试的新手。我有一个工作单元,我正在尝试进行单元测试。我可能错过了一些简单的东西。我正在尝试对提交方法进行单元测试。我正在使用nunit和moq public class UnitOfWork : IUnitOfWork { private readonly DbContext _context; public UnitOfWork(DbContext ctx) { _context = ctx; } public void Com
public class UnitOfWork : IUnitOfWork
{
private readonly DbContext _context;
public UnitOfWork(DbContext ctx)
{
_context = ctx;
}
public void Commit()
{
_context.SaveChanges();
}
}
我需要做什么来测试这一点?您需要模拟DbContext,然后验证是否调用了SaveChanges。类似Moq的东西可以帮助您。您可以插入DBContext的模拟,然后验证是否在提交时调用了SaveChanges方法
[Test]
public void Will_call_save_changes() {
var mockContext = new Mock<DBContext>();
var unitOfWork = new UnitOfWork(mockContext.Object);
unitOfWork.Commit();
mockContext.Verify(x => x.SaveChanges());
}
[测试]
public void将调用保存更改(){
var mockContext=new Mock();
var unitOfWork=新的unitOfWork(mockContext.Object);
unitOfWork.Commit();
验证(x=>x.SaveChanges());
}
这是一种方法
我遇到的另一种选择是:
创建edmx文件,删除自定义工具,使其不会自动生成实体
打开edmx文件,右键单击并添加代码生成项目-转到数据库下的联机模板并选择EF POCO mockobject生成器。这将创建两个T4模板(一个用于实体,另一个用于对象上下文和模拟对象上下文)
one T4模板将为您生成poco实体。另一个T4模板将创建一个可扩展的接口,以用作在实际对象上下文和模拟对象上下文中实现的工作单元。扩展它只需要修改T4模板,以便在生成的接口(void SaveChanges())上包含一个附加方法,并在模拟对象上下文上实现该方法
我发现它工作得很好
尽管出于单元测试的目的,您不想测试您的工作单元(除非验证添加/删除了某些对象等)。相反,您应该使用预定义的职责测试存储库-通常在上下文中定义(例如患者预约)
你可以这样做:
public class PatientAppointmentRepository : IPatientAppointmentRepository
{
//Injected via IOC in constructor
private readonly IUnitOfWork _unitOfWork;
private readonly IPatientAppointmentLogic _patientAppointmentLogic;
public void CreateAppointment(PatientAppointmentModel model)
{
var appointment = ModelMapper.Instance.To<PatientAppointment>(model);
var appointmentAdded = _patientAppointmentLogic.Add(appointment);
if(appointmentAdded)
_unitOfWork.SaveChanges();
}
}
public class PatientAppointmentLogic : IPatientAppointmentLogic
{
private readonly IUnitOfWork _unitOfWork; //Set via constructor
private readonly PatientLogic _patientLogic;
public bool Validate(PatientAppointment appointment)
{
if(appointment == null)
throw new ArgumentNullException("appointment");
//perform some logic here
return true;
}
public void Add(PatientAppointment appointment)
{
if(appointment == null)
throw new ArgumentNullException("appointment");
if(!Validate(appointment)) return; //Or throw an exception, up to you
var patient = _patientLogic.GetById(appointment.PatientId);
if(patient == null) return;
patient.PatientAppointments.Add(appointment);
}
}
公共类PatientPointmentRepository:iPatientAppointRepository
{
//在构造函数中通过IOC注入
私人只读i工作单元(unitof工作单元);;
专用只读iPartientAppointLogic _patientAppointLogic;
public void CreateAppointment(PatientPointmentModel)
{
var appointment=ModelMapper.Instance.To(model);
var AppointAdded=\u PatientAppointLogic.Add(约会);
如果(新增任命)
_unitOfWork.SaveChanges();
}
}
公共类PatientAppointLogic:iPatientAppointLogic
{
私有只读IUnitOfWork _unitOfWork;//通过构造函数设置
私有只读PatientLogic\u PatientLogic;
公共bool验证(预约)
{
如果(约会==null)
抛出新的异常(“约会”);
//在这里执行一些逻辑
返回true;
}
公共无效添加(任命)
{
如果(约会==null)
抛出新的异常(“约会”);
如果(!Validate(appointment))返回;//或引发异常,则由您决定
var patient=\u patientLogic.GetById(appointment.PatientId);
if(patient==null)返回;
患者。患者药膏。添加(预约);
}
}
这真的取决于你如何恰当地构建它。您可以有另一个AppointLogic存储库,以基本验证为例
理想情况下,通用验证不应依赖于外部资源(如数据库)
您应该能够一次性创建一个验证上下文,用于进一步的验证(在“昂贵地”验证之前,先“便宜地”验证)
有时,验证所需的所有“值”都位于您无论如何都需要的实体内,然后将其用作验证上下文
祝你好运