单元测试一个工作单元

本文关键字:一个 工作 单元 单元测试 | 更新日期: 2023-09-27 17:59:13

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

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

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

单元测试一个工作单元

您可以插入DBContext的mock,然后验证在提交时是否调用了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());
}

您需要模拟DbContext,然后验证是否调用了SaveChanges。像莫这样的人可以在这里帮助你。

这是一种方法。

我遇到的另一种选择是:

创建你的edmx文件,删除自定义工具,这样它就不会自动生成实体。

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

一个T4模板将为您生成您的poco实体。另一个T4模板将创建一个接口,您可以扩展该接口以用作在实际对象上下文和模拟对象上下文中实现的工作单元。扩展它只需要修改T4模板,在生成的接口上包括一个额外的方法(void SaveChanges()),并在mock对象上下文上实现该方法。

我发现它工作得很好。

即使是出于单元测试的目的,你也不想测试你的工作单元(除非验证是否添加/删除了某些对象等)。相反,你会测试具有预定义职责的存储库-通常在上下文中定义(例如,患者预约)。

你可以这样做:

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

这真的取决于你是否合理地构建它。您可以使用另一个具有基本验证的AppointmentLogic存储库作为示例。

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

您应该能够一次性创建一个验证上下文,该上下文将用于进一步的验证(首先"廉价"有效,然后"昂贵"验证)。

有时,验证所需的所有"值"都在您无论如何都需要的实体中,然后将其用作验证上下文。

祝你好运!