是否有另一种方法可以在mvc中对业务逻辑进行单元测试

时间:2015-06-09 07:31:39

标签: c# unit-testing asp.net-mvc-5 moq repository-pattern

我手动为mvc5应用程序添加了单元测试。 这是我的业务逻辑

public void AddTreatments(TreatmentView model)
{
    using(var treatment = new TreatmentRepository())
    {
        var treat = new PhysiqueData.ModelClasses.Treatment()
        {
            treatmentID = model.treatmentID,
            treatmentCost = model.treatmentCost,
            treatmentDuration = model.treatmentDuration,
            treatmentName = model.treatmentName
        }
        treatment.Insert(treat);
    }
}

这是我在服务层中使用的存储库

public class TreatmentRepository:ITreatmentRepository
{
    private ApplicationDbContext _datacontext;
    private readonly IRepository<Treatment> _treatmentRepository;

    public TreatmentRepository()
    {
        _datacontext = new ApplicationDbContext();
        _treatmentRepository = new RepositoryService<Treatment>(_datacontext);
    }

    public void Insert(Treatment model)
    {
        _treatmentRepository.Insert(model);
    }
}

下一个代码是我的治疗实际单位测试,它不起作用, 我可以得到一些指导。我搜索了很多东西,仍然无法做到正确。

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void AddingTreatmenttodatabase()
    {
        //var business = new TreatmentBusiness(new TreatmentRepository());

        var treatment = new Treatment()
        {
            treatmentID = 1,
            treatmentCost = 250,
            treatmentDuration = 45,
            treatmentName = "LowerBack"
        };

        var repositoryMock = new Mock<ITreatmentRepository>();
        repositoryMock.Setup(x => x.Insert(treatment));

        var business = new TreatmentBusiness(repositoryMock.Object);

        business.AddTreatments(treatment);

        repositoryMock.Verify(x => x.Insert(treatment), Times.Once());
    }
}

1 个答案:

答案 0 :(得分:5)

因此,您要实例化ITreatmentRepository的模拟,设置一些行为并将其注入TreatmentBusiness课程。到现在为止还挺好。

但是,在您的AddTreatments方法中,您实例化了一个新的TreatmentRepository,而不是使用通过构造函数注入的那个。{/ p>

我假设您的构造函数看起来像这样:

public class TreatmentBusiness
{
    private readonly ITreatmentRepository repository;

    public TreatmentBusiness(ITreatmentRepository repository)
    {
        this.repository = repository;
    }

    ...
}

在这种情况下,您的方法应如下所示:

public void AddTreatments(TreatmentView model)
{
    using (var treatment= this.repository)
    {
        var treat = new PhysiqueData.ModelClasses.Treatment();
        {
            treat.treatmentID = model.treatmentID;
            treat.treatmentCost = model.treatmentCost;
            treat.treatmentDuration = model.treatmentDuration;
            treat.treatmentName = model.treatmentName;
        }
        treatment.Insert(treat);
    }
}

注意字段repository的用法,而不是实例化新字段。

根据Jimmy_keen的建议,为了确保您的存储库在整个课程中得到适当的实例化和访问,建议您选择工厂。

有几种方法可以实现存储库工厂,要么手动创建专用工厂并将其注入构造函数,如下所示:

public class TreatmentBusiness
{
    private readonly ITreatmentRepositoryFactory repositoryFactory;

    public TreatmentBusiness(ITreatmentRepositoryFactory repositoryFactory)
    {
        this.repositoryFactory = repositoryFactory;
    }

    ...
}

这会改变您访问存储库的方式,如下所示:

public void AddTreatments(TreatmentView model)
{
    using (var treatment= this.repositoryFactory.Make())
    //or whatever method name you've chosen on your factory

如果你觉得这太过分了,你可以选择一个方法委托(Func<>)并注入一个实例化新TreatmentRepository的方法。

这会改变你的构造函数:

public class TreatmentBusiness
{
    private readonly Func<TreatmentRepository> getTreatmentRepository;

    public TreatmentBusiness(Func<TreatmentRepository> getTreatmentRepository)
    {
            this.getTreatmentRepository = getTreatmentRepository;
    }
    ....
}

你会改变你的方法:

public void AddTreatments(string model)
{
    using (var treatment = this.getTreatmentRepository()) //Or this.getTreatmentRepository.Invoke() - same thing
    {
        ...
    }
}

解决该依赖关系的方式取决于您,可以手动执行,也可以在实例化Business对象时注入该委托:

var treatmentBusiness = new TreatmentBusiness(() => new TreatmentRepository());

或者您可以使用众多IoC容器/ DI框架中的一个。