C# 你如何为单元测试设计一门课

C# 你如何为单元测试设计一门课,c#,asp.net-mvc,unit-testing,mocking,moq,C#,Asp.net Mvc,Unit Testing,Mocking,Moq,此问题作为后续问题发布 自从提出最初的问题以来,我现在创建了一个最小的、完整的和可验证的示例,作为这个问题的基础 我有一个控制器如下所示 public class HomeController : Controller { private OrganisationLogic _organisationLogic; public HomeController(OrganisationLogic logic) { _organisationLogic = ne

此问题作为后续问题发布

自从提出最初的问题以来,我现在创建了一个最小的、完整的和可验证的示例,作为这个问题的基础

我有一个控制器如下所示

public class HomeController : Controller
{
    private OrganisationLogic _organisationLogic;

    public HomeController(OrganisationLogic logic)
    {
       _organisationLogic = new OrganisationLogic();
    }

    public ActionResult Index()
    {
        var model = _organisationLogic.GetOrganisation().ToViewModel();
        return View(model);
    }
}
 public class OrganisationLogic : LogicRepository<OrganisationModel>
 {
     public OrganisationLogic()
     {

     }

     public override OrganisationModel GetOrganisation()
     {

         return new OrganisationModel { Id = 1, OrganisationName = "My Orgaisation", Address = "Logic" };

     }
}
public abstract class LogicRepository<T> : ILogicRepository<T>
{

    protected LogicRepository()
    {

    }


    public abstract T GetOrganisation();

 }
public interface ILogicRepository<TModel>
{
    TModel GetOrganisation();
}
控制器从名为OrganizationLogic的业务逻辑层中的方法检索数据,如下所示

public class HomeController : Controller
{
    private OrganisationLogic _organisationLogic;

    public HomeController(OrganisationLogic logic)
    {
       _organisationLogic = new OrganisationLogic();
    }

    public ActionResult Index()
    {
        var model = _organisationLogic.GetOrganisation().ToViewModel();
        return View(model);
    }
}
 public class OrganisationLogic : LogicRepository<OrganisationModel>
 {
     public OrganisationLogic()
     {

     }

     public override OrganisationModel GetOrganisation()
     {

         return new OrganisationModel { Id = 1, OrganisationName = "My Orgaisation", Address = "Logic" };

     }
}
public abstract class LogicRepository<T> : ILogicRepository<T>
{

    protected LogicRepository()
    {

    }


    public abstract T GetOrganisation();

 }
public interface ILogicRepository<TModel>
{
    TModel GetOrganisation();
}
业务逻辑稍后继承如下所示的逻辑存储库

public class HomeController : Controller
{
    private OrganisationLogic _organisationLogic;

    public HomeController(OrganisationLogic logic)
    {
       _organisationLogic = new OrganisationLogic();
    }

    public ActionResult Index()
    {
        var model = _organisationLogic.GetOrganisation().ToViewModel();
        return View(model);
    }
}
 public class OrganisationLogic : LogicRepository<OrganisationModel>
 {
     public OrganisationLogic()
     {

     }

     public override OrganisationModel GetOrganisation()
     {

         return new OrganisationModel { Id = 1, OrganisationName = "My Orgaisation", Address = "Logic" };

     }
}
public abstract class LogicRepository<T> : ILogicRepository<T>
{

    protected LogicRepository()
    {

    }


    public abstract T GetOrganisation();

 }
public interface ILogicRepository<TModel>
{
    TModel GetOrganisation();
}
逻辑存储库实现如下所示的ILogicRecepository接口

public class HomeController : Controller
{
    private OrganisationLogic _organisationLogic;

    public HomeController(OrganisationLogic logic)
    {
       _organisationLogic = new OrganisationLogic();
    }

    public ActionResult Index()
    {
        var model = _organisationLogic.GetOrganisation().ToViewModel();
        return View(model);
    }
}
 public class OrganisationLogic : LogicRepository<OrganisationModel>
 {
     public OrganisationLogic()
     {

     }

     public override OrganisationModel GetOrganisation()
     {

         return new OrganisationModel { Id = 1, OrganisationName = "My Orgaisation", Address = "Logic" };

     }
}
public abstract class LogicRepository<T> : ILogicRepository<T>
{

    protected LogicRepository()
    {

    }


    public abstract T GetOrganisation();

 }
public interface ILogicRepository<TModel>
{
    TModel GetOrganisation();
}
我想对HomeController进行单元测试,以验证ViewModel中显示的数据是否正确地从OrganizationLogic返回,并从OrganizationModel转换为OrganizationViewModel

我编写了以下UnitTest,它使用Moq模拟方法&u OrganizationLogic.getOrganization

[TestMethod]
public void Index()
{

    var _OrganisationLogic = new Mock<OrganisationLogic>();

    var testdata = new OrganisationModel { Id = 3, OrganisationName = "My Test Class Organisation" };

    _OrganisationLogic.Setup(p => p.GetOrganisation()).Returns(testdata).Callback<OrganisationModel>(p=>p = testdata);

    HomeController controller = new HomeController(_OrganisationLogic.Object);
    ViewResult result = controller.Index() as ViewResult;
    OrganisationViewModel model = (OrganisationViewModel)result.Model; 

    Assert.AreEqual(testdata.OrganisationName,model.OrganisationName);
}
当我运行测试时,测试失败。原因是Mock没有重写该类,而是从BusinessLogic层中的实际方法返回结果

在我最初的问题中,我发布的错误消息是:

System.ArgumentException无效回调。具有0个参数的方法上的安装程序无法使用不同数量的参数1调用回调。Source=Moq StackTrace:at Moq.MethodCallReturn2.ValidateNumberOfCallbackParametersMethodInfo Moq.MethodCallReturn2.ValidateReturnDelegateDelegateDelegate调用Moq.MethodCallReturn2.Returns[T]Func2值表达式

我现在能够通过运行下面的单元测试准确地复制这个错误消息。我怀疑上面的单元测试更接近我所需要的,在下面的例子中,我设置的返回错误。欢迎对此发表意见

[TestMethod]
public void Index()
{

     var _OrganisationLogic = new Mock<OrganisationLogic>();

     var testdata = new OrganisationModel { Id = 3, OrganisationName = "My Test Class Organisation" };

     _OrganisationLogic.Setup(p => p.GetOrganisation()).Returns<OrganisationModel>(p=>p = testdata).Callback<OrganisationModel>(p=>p = testdata);

     HomeController controller = new HomeController(_OrganisationLogic.Object);
     ViewResult result = controller.Index() as ViewResult;
     OrganisationViewModel model = (OrganisationViewModel)result.Model; 

     Assert.AreEqual(testdata.OrganisationName,model.OrganisationName);
}
我的问题是如何设置Mock,以便它使用我的测试数据

为了帮助回答上述问题,我在GitHub上放置了一个版本的代码,它演示了这个问题,并显示测试失败。可访问以下网址:


非常感谢您的帮助。

更改HomeController的构造函数,使参数类型为ILogicRespository,字段也需要该类型,并使用注入构造函数的实例_组织逻辑=逻辑;上面的代码忽略了参数,并创建了OrganizationLogic自己的具体实例,这意味着它没有使用模拟对象

在测试中,将组织逻辑的声明更改为。。。 var _OrganizationLogic=新模拟

正如我之前问过的,我认为你不需要回电话

编辑的构造函数将如下所示

private ILogicRepository<OrganisationModel> _organisationLogic;

public HomeController(ILogicRepository<OrganisationModel> logic)
{
   _organisationLogic = logic;
}

更改HomeController的构造函数,使参数类型为ILogicRepository,字段也需要该类型,并使用注入构造函数的实例_组织逻辑=逻辑;上面的代码忽略了参数,并创建了OrganizationLogic自己的具体实例,这意味着它没有使用模拟对象

在测试中,将组织逻辑的声明更改为。。。 var _OrganizationLogic=新模拟

正如我之前问过的,我认为你不需要回电话

编辑的构造函数将如下所示

private ILogicRepository<OrganisationModel> _organisationLogic;

public HomeController(ILogicRepository<OrganisationModel> logic)
{
   _organisationLogic = logic;
}

请你改变我的构造器上面,并张贴完成的构造器?我很难理解你的所有建议:我已经取消了回调,我得到了相同的错误是的,因为在返回代码部分失败,在它到达回调之前。太好了!考试通过了!谢谢你的帮助!对于在我将工作版本提交给git之后出现的任何人!谢谢-老实说,如果我首先创建MCVE,我会走得更快-今晚我花了2个小时来制作MCVE并在原始项目中解决问题;在今晚之前,我浪费了三天时间试图解决这个问题。它只是去表明一点点努力真的有回报!请你改变我的构造器上面,并张贴完成的构造器?我很难理解你的所有建议:我已经取消了回调,我得到了相同的错误是的,因为在返回代码部分失败,在它到达回调之前。太好了!考试通过了!谢谢你的帮助!对于在我将工作版本提交给git之后出现的任何人!谢谢-老实说,如果我首先创建MCVE,我会走得更快-今晚我花了2个小时来制作MCVE并在原始项目中解决问题;在今晚之前,我浪费了三天时间试图解决这个问题。它只是去表明一点点努力真的有回报!