2011-06-14 108 views
12

新的单元测试。我有一个工作单元,我正在尝试进行单元测试。我可能在这里错过简单的东西。我想单元测试Commit方法。我正在使用nunit和moq。单元测试工作单元

public class UnitOfWork : IUnitOfWork 
{ 
    private readonly DbContext _context; 
    public UnitOfWork(DbContext ctx) 
    { 
     _context = ctx; 
    } 

    public void Commit() 
    { 
     _context.SaveChanges(); 
    } 
} 

我需要做什么来测试这个?

回答

16

您会插入一个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()); 

} 
1

您需要模拟DbContext,然后验证是否调用了SaveChanges。像Moq这样的东西可以帮助你。

0

这是做到这一点的一种方式。

我遇到另一种方法是:

创建EDMX文件,删除自定义工具,所以它不会自动生成的实体。

打开edmx文件,右键单击并添加代码生成项 - 转到数据库下的在线模板并选择EF POCO mockobject生成器。这将创建两个T4模板(一个用于实体,另一个用于对象上下文和模拟对象上下文)。

一个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); 
    } 
} 

这真的取决于你对appropiately构建它。您可以将另一个基本验证的AppointmentLogic存储库作为示例。

理想情况下,通用验证不应该依赖外部资源(如数据库)。

您应该能够创建一个验证上下文,用于进一步验证(在验证'代价高昂'之前首先有效'便宜')。

有时您验证所需的所有“值”都在您需要的实体内部,然后将其用作验证上下文。

祝你好运!