C# 模拟对象无法返回所需的对象

C# 模拟对象无法返回所需的对象,c#,asp.net-mvc-3,nunit,moq,ninject-2,C#,Asp.net Mvc 3,Nunit,Moq,Ninject 2,当我遇到这样的问题时,总会有一些明显的事情我忽略了 我有一个控制器,它只根据提供的ID返回一篇新闻文章: [HandleError] public class HomeController : Controller { private readonly IArticleRepository articleRepository; public HomeController(IArticleRepository Repository) { articleRe

当我遇到这样的问题时,总会有一些明显的事情我忽略了

我有一个控制器,它只根据提供的ID返回一篇新闻文章:

[HandleError]
public class HomeController : Controller
{
    private readonly IArticleRepository articleRepository;

    public HomeController(IArticleRepository Repository)
    {
        articleRepository = Repository;
    }

    public ActionResult Index()
    {
        return View("Index");
    }

    // Here's the bit we're interested in
    public ActionResult Article(int id)
    {
        var article = articleRepository.GetById(id);

        return View("Article", article);
    }

}
我用最小起订量来模拟它,就像这样:

[TestFixture]
public class HomeControllerTests
{
    HomeController controller;
    int articleId;
    Article model;

    [TestFixtureSetUp]
    public void SetupMethods()
    {
        Mock<IArticleRepository> repositoryMock = new Mock<IArticleRepository>();
        repositoryMock.Setup(x => x.GetById(articleId)).Returns(GetSampleArticle());

        controller = new HomeController(repositoryMock.Object);
    }

    [Test]
    public void Article_Action_Returns_Requested_Article()
    {
        // Arrange
        model = new Article();
        articleId = 1;

        // Act
        ActionResult result = controller.Article(articleId);

        // Assert
        var viewResult = ((ViewResult)result);
        var returnedModel = viewResult.Model;
        Assert.IsInstanceOf<Article>(viewResult.Model);
        //Assert.AreEqual(articleId, returnedModel.ID);
    }
}
[TestFixture]
公共类家庭控制器测试
{
家庭控制器;
int articleId;
文章模式;
[TestFixtureSetUp]
公共方法()
{
Mock repositoryMock=新建Mock();
Setup(x=>x.GetById(articleId)).Returns(GetSampleArticle());
控制器=新的HomeController(repositoryMock.Object);
}
[测试]
公共无效文章\行动\返回\请求\文章()
{
//安排
模型=新文章();
articleId=1;
//表演
ActionResult=controller.Article(articleId);
//断言
var viewResult=((viewResult)结果);
var returnedModel=viewResult.Model;
Assert.IsInstanceOf(viewResult.Model);
//aresequal(articleId,returnedModel.ID);
}
}
上面提到的“GetSampleArticle”方法如下所示:

    private Article GetSampleArticle()
    {
        Article article = new Article()
        {
            Archived = false,
            Body = "<p>This is a dummy sample article for use in our mocks.</p>",
            EndDate = DateTime.Today.AddDays(30),
            ID = 1,
            Priority = 3,
            StartDate = DateTime.Today,
            Title = "Sample Article"
        };

        return article;
    }
私有文章GetSampleArticle()
{
第条=新条款()
{
存档=假,
Body=“这是一篇用于模拟的虚拟示例文章。

”, EndDate=DateTime.Today.AddDays(30), ID=1, 优先级=3, StartDate=日期时间。今天, Title=“示例文章” }; 退货物品; }
但是,我仍然得到模型的null类型。那么我忘记了什么

News.Tests.Controllers.HomeControllerTests.Article_Action_Returns_Requested_Article:
  Expected: instance of <News.Data.Article>
  But was:  null
News.Tests.Controllers.HomeControllerTests.Article\u Action\u返回\u请求的\u文章:
预期:实例
但是是:空

在SetupMethods中,articleId为0

在测试中,您将其设置为1,因此永远不会调用
.Setup
。我会将您的设置移动到您的测试中

[Test]
public void Article_Action_Returns_Requested_Article()
{
    // Arrange
    model = new Article();
    articleId = 1;

    Mock<IArticleRepository> repositoryMock = new Mock<IArticleRepository>();
    repositoryMock.Setup(x => x.GetById(articleId)).Returns(GetSampleArticle());

    controller = new HomeController(repositoryMock.Object);

    // Act
    ActionResult result = controller.Article(articleId);

    // Assert
    var viewResult = ((ViewResult)result);
    var returnedModel = viewResult.Model;
    Assert.IsInstanceOf<Article>(viewResult.Model);
    //Assert.AreEqual(articleId, returnedModel.ID);
}
[测试]
公共无效文章\行动\返回\请求\文章()
{
//安排
模型=新文章();
articleId=1;
Mock repositoryMock=新建Mock();
Setup(x=>x.GetById(articleId)).Returns(GetSampleArticle());
控制器=新的HomeController(repositoryMock.Object);
//表演
ActionResult=controller.Article(articleId);
//断言
var viewResult=((viewResult)结果);
var returnedModel=viewResult.Model;
Assert.IsInstanceOf(viewResult.Model);
//aresequal(articleId,returnedModel.ID);
}

在SetupMethods中,articleId为0

在测试中,您将其设置为1,因此永远不会调用
.Setup
。我会将您的设置移动到您的测试中

[Test]
public void Article_Action_Returns_Requested_Article()
{
    // Arrange
    model = new Article();
    articleId = 1;

    Mock<IArticleRepository> repositoryMock = new Mock<IArticleRepository>();
    repositoryMock.Setup(x => x.GetById(articleId)).Returns(GetSampleArticle());

    controller = new HomeController(repositoryMock.Object);

    // Act
    ActionResult result = controller.Article(articleId);

    // Assert
    var viewResult = ((ViewResult)result);
    var returnedModel = viewResult.Model;
    Assert.IsInstanceOf<Article>(viewResult.Model);
    //Assert.AreEqual(articleId, returnedModel.ID);
}
[测试]
公共无效文章\行动\返回\请求\文章()
{
//安排
模型=新文章();
articleId=1;
Mock repositoryMock=新建Mock();
Setup(x=>x.GetById(articleId)).Returns(GetSampleArticle());
控制器=新的HomeController(repositoryMock.Object);
//表演
ActionResult=controller.Article(articleId);
//断言
var viewResult=((viewResult)结果);
var returnedModel=viewResult.Model;
Assert.IsInstanceOf(viewResult.Model);
//aresequal(articleId,returnedModel.ID);
}

另一个想法是使用It.IsAny()方法来避免查找硬编码值:

repositoryMock.Setup(x => x.GetById(It.IsAny<int>())).Returns(GetSampleArticle());
repositoryMock.Setup(x=>x.GetById(It.IsAny()).Returns(GetSampleArticle());

这样做是安全的,因为您不关心articleId的实际值,而是关心它的检索机制。

另一个想法是使用It.IsAny()方法来避免查找硬编码值:

repositoryMock.Setup(x => x.GetById(It.IsAny<int>())).Returns(GetSampleArticle());
repositoryMock.Setup(x=>x.GetById(It.IsAny()).Returns(GetSampleArticle());

这样做是安全的,因为你关心的不是articleId的实际值,而是它的检索机制。

好极了。非常感谢。实际上,我将它移动到NUnit[SetUp]修饰的方法中,而不是每次测试都声明它。很好,太棒了。非常感谢。实际上,我将它移动到NUnit[SetUp]修饰的方法中,而不是每次测试都声明它。很好,完全同意。您不应该为设置指定值。相反,当您想要验证值本身时,应该使用Expect(),尽管这是我自己不再做的事情,因为快速阅读代码会告诉我a是否正确地分配给B。甚至更好。我一直想学习更多关于如何更好地使用Moq语法的知识,这是一个非常有用的例子。谢谢。我建议不要在单元测试中使用
IsAny
,除非你必须这样做。它使测试变得脆弱,因为您无法确切地确定传入的内容,也无法确定返回的数据是否正确。如果您传递的是
articleId
而不是
IsAny
,那么您就知道正在使用正确的参数调用
GetById
。这只会让测试更可靠,让你更有信心,因为正确的理由它会通过。这是一个很好的建议,我很感激,但在这种情况下,因为我实际上并不特别关心通过的实际值;只需返回一条伪记录,
IsAny
方法就应该适合这种情况。完全同意。您不应该为设置指定值。相反,当您想要验证值本身时,应该使用Expect(),尽管这是我自己不再做的事情,因为快速阅读代码会告诉我a是否正确地分配给B。甚至更好。我一直想学习更多关于如何更好地使用Moq语法的知识,这是一个非常有用的例子。谢谢。我建议不要在单元测试中使用
IsAny
,除非你必须这样做。它可以进行测试