此问题已作为How do you Mock an class for a unit test that has a return type but no input parameters
的后续跟进发布自从问起原来的问题后,我现在创建了一个最小的,完整的,可验证的例子,作为这个问题的基础。
我有一个控制器(如下所示)
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);
}
}
控制器从业务逻辑层中名为OrganisationLogic的方法(如下所示)中检索数据
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();
}
Logic Repository实现了ILogicRepository接口(如下所示)
public interface ILogicRepository<TModel>
{
TModel GetOrganisation();
}
我想对HomeController进行单元测试,以验证ViewModel中显示的数据是否已从OrganisationLogic正确返回并从OrganisationModel转换为OrganisationViewModel。
我编写了以下UnitTest,它使用Moq来模拟方法_OrganisationLogic.GetOrganisation()。
[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:在Moq.MethodCallReturn2.ValidateNumberOfCallbackParameters(MethodInfo) callbackMethod)在Moq.MethodCallReturn2.ValidateReturnDelegate(委托回调)在Moq.MethodCallReturn2.Returns [T](Func2 valueExpression)
我现在能够通过运行以下单元测试来完全复制此错误消息。我怀疑上面的单元测试更接近我需要的,并且在下面的实例中我错误地设置了Return()。对此的想法是受欢迎的?
[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上放置了一个代码版本,用于演示此问题并显示测试失败。这可以在https://github.com/stephenwestgarth/UnitTestExample
访问非常感谢任何帮助。
答案 0 :(得分:4)
更改HomeController的构造函数,使参数类型为ILogicRepository<OrganisationModel>
,字段也需要该类型,并使用注入构造函数的实例。 _organisationLogic = logic;
(上面的代码忽略了参数并创建了自己的OrganisationLogic具体实例,这意味着它没有使用你的模拟对象。
在测试中将_OrganisationLogic的声明更改为......
var _OrganisationLogic = new Mock<ILogicRepository<OrganisationModel>>();
正如我之前所说的那样,我认为你不需要回调。
编辑的构造函数看起来像这样......
private ILogicRepository<OrganisationModel> _organisationLogic;
public HomeController(ILogicRepository<OrganisationModel> logic)
{
_organisationLogic = logic;
}