Skip to main content
Code Review

Return to Question

deleted 57 characters in body; edited title
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

Concerns about the correctness of my Repository and Controller tests

In order to demonstrate what I have tried so far and to give you folks something to go on - here is an example SUT...

  • Starting with the repository. Are - are my repository tests correct?
  • Given correct repository tests - are my controller tests correct?

A correct test in my mind is one that is purposeful and thorough. Are my tests correct and throughthorough?

I also welcome additional review of any kind.

Concerns about the correctness of my Repository and Controller tests

In order to demonstrate what I have tried so far and to give you folks something to go on - here is an example SUT...

  • Starting with the repository. Are my repository tests correct?
  • Given correct repository tests - are my controller tests correct?

A correct test in my mind is one that is purposeful and thorough. Are my tests correct and through?

I also welcome additional review of any kind.

Repository and Controller tests

In order to demonstrate what I have tried so far and to give you folks something to go on - here is an example SUT.

  • Starting with the repository - are my repository tests correct?
  • Given correct repository tests - are my controller tests correct?

A correct test in my mind is one that is purposeful and thorough. Are my tests correct and thorough?

Notice removed Canonical answer required by Community Bot
Bounty Ended with Ben Aaronson's answer chosen by Community Bot
Tweeted twitter.com/#!/StackCodeReview/status/498597026415017984
Notice added Canonical answer required by Caster Troy
Bounty Started worth 50 reputation by Caster Troy
edited tags
Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238
Source Link
Caster Troy
  • 721
  • 4
  • 11

Concerns about the correctness of my Repository and Controller tests

Lately I have been researching how to best unit test an EF repository and given a properly tested repository, what to test in the controller.

My research did not reveal many sound examples or explanations but I did what I could. Now I am kindly asking that you review my tests in order to verify their correctness.

Example SUT

In order to demonstrate what I have tried so far and to give you folks something to go on - here is an example SUT...

I am coding a small blog engine. I have a controller by the name of PostsController whose role is obvious:

public class PostsController : Controller
{
 private readonly IPostsRepository repository;
 private readonly IMappingEngine mapper;
 public PostsController(IPostsRepository repository, IMappingEngine mapper)
 {
 this.repository = repository;
 this.mapper = mapper;
 }
 public ViewResult Index()
 {
 var posts = repository.GetAllPublished();
 var model =
 mapper.Map<IEnumerable<PostViewModel>>(posts);
 return View("Index", model);
 }
}

In an attempt to keep my controllers thin (and to achieve lose coupling) I introduced a repository by the name of PostsRepository who implements an interface called IPostsRepository:

public interface IPostsRepository
{
 IEnumerable<Post> All();
 IEnumerable<Post> GetAllPublished();
}
public class PostsRepository : IPostsRepository
{
 private readonly DatabaseContext context;
 public PostsRepository(DatabaseContext context)
 {
 this.context = context;
 }
 public IEnumerable<Post> All()
 {
 return 
 context.Posts
 .OrderBy(post => post.PublishDate);
 }
 public IEnumerable<Post> GetAllPublished()
 {
 return 
 context.Posts
 .Where(post => !post.Draft)
 .OrderBy(post => post.PublishDate);
 }
}

Note that only one of the two methods defined by the repository interface are actually used by the controller in this example. I included the ineffectual method to better reflect a real-world example as that is important to me. I included the IMappingEngine abstraction (that comes from AutoMapper) for the same reason.

My best efforts at testing this system

Having amalgamated a number of articles and videos I came up with the following unit tests:

[TestFixture]
public class PostsControllerTest
{
 private PostsController controller;
 private Mock<IPostsRepository> repository;
 private Mock<IMappingEngine> mapper;
 [SetUp]
 public void SetUp()
 {
 repository = new Mock<IPostsRepository>();
 mapper = new Mock<IMappingEngine>();
 controller = new PostsController(repository.Object, mapper.Object);
 }
 [Test]
 public void Index_ReturnsCorrectViewName()
 {
 var actual = controller.Index();
 Assert.AreEqual("Index", actual.ViewName);
 }
 [Test]
 public void Index_UsesPostsRepository()
 {
 controller.Index();
 repository.Verify(repo => repo.GetAllPublished(), Times.Once);
 }
 [Test]
 public void Index_ReturnsCorrectModel()
 {
 var posts = Enumerable.Repeat(new PostViewModel(), 2).ToList();
 mapper.Setup(m => 
 m.Map<IEnumerable<PostViewModel>>(It.IsAny<IEnumerable<Post>>()))
 .Returns(posts);
 var actual = controller.Index().Model;
 Assert.IsAssignableFrom<List<PostViewModel>>(actual);
 }
}
[TestFixture]
public class PostsRepositoryTest
{
 private IQueryable<Post> posts;
 private Mock<DbSet<Post>> databaseSet;
 private Mock<DatabaseContext> databaseContext;
 private PostsRepository repository;
 public void SetUp()
 {
 databaseSet = new Mock<DbSet<Post>>();
 databaseSet.As<IQueryable<Post>>().Setup(query => query.Provider)
 .Returns(posts.Provider);
 databaseSet.As<IQueryable<Post>>().Setup(query => query.Expression)
 .Returns(posts.Expression);
 databaseSet.As<IQueryable<Post>>().Setup(query => query.ElementType)
 .Returns(posts.ElementType);
 databaseSet.As<IQueryable<Post>>().Setup(query => query.GetEnumrator())
 .Returns(posts.GetEnumerator);
 databaseContext = new Mock<DatabaseContext>();
 databaseContext.Setup(context => context.Posts)
 .Returns(databaseSet.Object);
 repository = new PostsRepository(databaseContext.Object);
 }
 [Test]
 public void All_ReturnsAll()
 {
 // arrange
 posts = Enumerable.Repeat(new Post(), 2).AsQueryable();
 // Because we need to setup the seed data (which varies for each test)
 // before mocking the database objects, we cannot use the NUnit SetUp 
 // attribute and must instead call SetUp manually *after* we setup the
 // seed data. 
 SetUp();
 // act
 var actual = repository.All();
 // assert
 Assert.AreEqual(2, actual.Count());
 }
 [Test]
 public void All_OrdersResultsByPublishDate()
 {
 // arrange
 posts = new List<Post>
 {
 new Post { PublishDate = new DateTime(2014, 1, 3) },
 new Post { PublishDate = new DateTime(2014, 1, 2) },
 new Post { PublishDate = new DateTime(2014, 1, 1) },
 }.AsQueryable();
 SetUp();
 // act
 var actual = repository.All();
 // assert
 var sorted = posts.OrderBy(post => post.PublishDate);
 CollectionAssert.AreEquivalent(actual, sorted);
 }
 [Test]
 public void GetAllPublished_ExcludesDrafts()
 {
 // arrange
 posts = new List<Post>
 {
 new Post(),
 new Post(), 
 new Post { Draft = true }
 }.AsQueryable();
 SetUp();
 // act
 var actual = repository.GetAllPublished();
 // assert
 Assert.AreEqual(2, actual.Count());
 }
 [Test]
 public void GetAllPublished_OrdersResultsByPublishDate()
 {
 // arrange
 posts = new List<Post>
 {
 new Post { PublishDate = new DateTime(2014, 1, 3) },
 new Post { PublishDate = new DateTime(2014, 1, 2) },
 new Post { PublishDate = new DateTime(2014, 1, 1) },
 }.AsQueryable();
 SetUp();
 // act
 var actual = repository.GetAllPublished();
 // assert
 var sorted = posts.OrderBy(post => post.PublishDate);
 CollectionAssert.AreEquivalent(actual, sorted);
 }
}

Particular areas of concern:

  • Starting with the repository. Are my repository tests correct?
  • Given correct repository tests - are my controller tests correct?

A correct test in my mind is one that is purposeful and thorough. Are my tests correct and through?

I also welcome additional review of any kind.

lang-cs

AltStyle によって変換されたページ (->オリジナル) /