我应该嘲笑还是伪造我的存储库?

时间:2014-07-28 06:37:07

标签: c# asp.net-mvc unit-testing

我有一个名为PostsController

的控制器
public class PostsController : Controller
{
    private const int PageSize = 8;
    private readonly IPostsRepository repository;

    public PostsController(IPostsRepository repository)
    {
        this.repository = repository;
    }

    public ViewResult Index(int pageNumber = 1)
    {
        var posts = 
            repository.All()
                      .Where(post => !post.Draft)
                      .OrderBy(post => post.PublishedAt);

        var model = 
            posts.MapTo<PostViewModel>()
                 .ToPagedList(pageNumber, PageSize);

        return View("Index", model);
    }

    public ActionResult Post(string slug)
    {
        var post =
            repository.Find(slug);

        if (post == null || post.Draft)
        {
            return HttpNotFound();
        }

        return View("Post", post.MapTo<PostViewModel>());
    }
}

一个名为PostsControllerTest

的相应测试夹具
[TestFixture]
public class PostsControllerTest
{
    private PostsController controller;
    private Mock<IPostsRepository> repository;

    [SetUp]
    public void SetUp()
    {
        AutoMapperConfig.Configure();
        repository = new Mock<IPostsRepository>();
        controller = new PostsController(repository.Object);
    }

    [Test]
    public void Index_ReturnsCorrectViewName()
    {
        var actual = controller.Index();

        Assert.AreEqual(actual.ViewName, "Index");
    }

    [Test]
    public void Index_ReturnsCorrectModel()
    {
        var result = controller.Index();
        var actual = result.Model as PagedList<PostViewModel>;

        Assert.NotNull(actual);
    }

    [Test]
    public void Index_WithPageNumber_ReturnsCorrectViewName()
    {
        var actual = controller.Index(2);

        Assert.AreEqual(actual.ViewName, "Index");
    }

    [Test]
    public void Index_WithPageNumber_ReturnsCorrectModel()
    {
        var result = controller.Index(2);
        var actual = result.Model as PagedList<PostViewModel>;

        Assert.NotNull(actual);
    }

    [Test]
    public void Post_ReturnsCorrectViewName()
    {
        repository.Setup(repo => repo.Find("abc"))
                  .Returns(new Post());

        var actual = controller.Post("abc") as ViewResult;

        Assert.NotNull(actual);
        Assert.AreEqual(actual.ViewName, "Post");
    }

    [Test]
    public void Post_ThatIsDraft_ReturnsNotFound()
    {
        var post = new Post { Draft = true };
        repository.Setup(repo => repo.Find("abc"))
                  .Returns(post);

        var actual = controller.Post("abc");

        Assert.IsAssignableFrom<HttpNotFoundResult>(actual);
    }

    [Test]
    public void Post_ThatDoesNotExist_ReturnNotFound()
    {
        var actual = controller.Post("abc");

        Assert.IsAssignableFrom<HttpNotFoundResult>(actual);
    }

    [Test]
    public void Post_ReturnsCorrectModel()
    {
        var post = new Post
        {
            Slug = "continuing-to-an-outer-loop",
            Title = "Continuing to an outer loop",
            Summary = "When you have a nested loop, sometimes",
            Content = "When you have a nested loop, sometimes",
            PublishedAt = DateTime.Now.AddDays(7),
            Tags = new Collection<Tag> { new Tag { Name = "Programming" } }
        };

        repository.Setup(repo => repo.Find("continuing-to-an-outer-loop"))
                  .Returns(post);

        var viewResult = (ViewResult)controller.Post("continuing-to-an-outer-loop");
        var actual = viewResult.Model as PostViewModel;

        Assert.NotNull(actual);
        Assert.AreEqual(actual.Slug, post.Slug);
        Assert.AreEqual(actual.Title, post.Title);
        Assert.AreEqual(actual.Summary, post.Summary);
        Assert.AreEqual(actual.Content, post.Content);
        Assert.AreEqual(actual.PublishedAt, post.PublishedAt);
        Assert.AreEqual(actual.Tags, post.Tags);
    }
}

我学会了通过观察其他项目如何安排测试来以这种方式模拟存储库。可以找到这种方法的一个特定示例(我从中学到)here。就个人而言,我发现这种方法有点费力。此外,自从采用这种方法后,我偶然发现this post表示你不应该嘲笑你的存储库而是假装它。

现在我很矛盾。 我应该继续模仿我的虚假存储库吗?

我恳请您提供代码示例,说明在这种情况下如何伪造和种子存储库,因为我不知道该怎么做。

1 个答案:

答案 0 :(得分:3)

为了选择一个方面,我说嘲笑很好,而且工作比伪造更少。

但是要发表意见 - 不要尴尬 - 我不会说......也不会。

考虑通过您的索引操作而不需要访问真实存储库的测试添加了多少值 - 您测试的绝大多数代码都在Linq和AutoMapper中,这两个代码都已经大量使用由其他人测试。

我建议编写 Integration 测试,这些测试贯穿您的控制器操作,通过您的真实存储库,点击您的数据库并返回到另一侧。这增加了价值,并为您提供了一个真正的保证,即您的系统( 您已经编写的位)实际上有效。

最后,Jimmy Bogard(AutoMapper成名)有一篇关于测试存储库here的博客文章。