4

I have written the following method using the Repository mentioned in the following blog-post (http://www.codecapers.com/post/Using-RavenDB-with-ASPNET-MVC.aspx) using RavenDB:

public User GetUserById(string id)
{
     var user = (from usr in _repository.All<User>() where usr.Id == id select usr).FirstOrDefault();

     if (user == null)
     {
          throw new NullReferenceException("No user with the id (" + id + ") could be found.");
     }

     return user;
}

How would you unit test this method with nunit (and perhaps moq)?

"user" is just a normal class.

Alexander
  • 1,021
  • 6
  • 20
  • 38

4 Answers4

2

Usualy you don't write tests directly against the repository layer. Say for example you are using nHibernate or Entity Framework, than wirting tests against the repository would technically be testing that framework.

The creators or those ORMs already done that.

Also talking to a database makes your test an integration test not a unit test.

Your unit test would be for example against the business layer mocking out the repository layer.

If you want to write an integration test you also write that against the business layer but don't mock the repository layer and let it go through.

Nope
  • 22,147
  • 7
  • 47
  • 72
  • This isn't about testing the repository layer. It's testing that the logic of the GetUserById method is correct, which it might not be. You can trust that the out of the box implementation of the repository of the correct, but that doesn't mean your code uses is correctly! – Dan Puzey Apr 24 '12 at 14:54
  • I only mentioned it, apologies if that made my answer unclear. I'm assuming GetUserById is a method in the business layer, so you would write an integration test against it if you want to check that the correct data is returned by the method. In your test you first insert the test data into the database, then execute your method and then assert the expected values are returned by the call. If you write a unit test you simply mock out the repository layer and set an expectation for GetUserById in the mocked object to ensure it is being called. – Nope Apr 24 '12 at 15:20
1

I would do the following to prepare your code:

  1. Make sure your _repository is being passed in through a constructor or property, so that it can be easily changed for tests.
  2. Make sure your _repository variable is declared as the IRepository type, rather than the concrete type.

Then, in your tests:

  1. Create a mock of your interface and pass this in to be your _repository.
  2. Override the .All<User>() method to return a known, hardcoded list of User with suitable values for your tests.
  3. Assert in one test that the correct value is returned when you query an existing ID.
  4. Assert in a separate test that the exception is thrown when you query a non-existant ID.
Dan Puzey
  • 33,626
  • 4
  • 73
  • 96
0

The first question is going to be - what are you testing in this context? The method provided really only has two outcomes, so you're basically testing whether user is null or not. Is that a value added test?

As for the how, Im assuming _repository is injected via some mechanism? If so, then you simply provide a Mock<IRepository> (insert your type name as appropriate) and inject that in the place of _repository wherever that is injected. Then you can setup the return values and test your method for the exception or not.

mockRepository.Setup(x => x.All<User>()).Returns(new List<User> { ... });
Tejs
  • 40,736
  • 10
  • 68
  • 86
  • 1
    No: you're also testing that your method returns the correct user. There's nothing to guarantee that `GetUserById("4")` returns a user with an Id of "4" unless you explicitly test for it. Assuming a repository of 10 `Users` there 11 possible outcomes *assuming I only return data from the repository*. So, if you're testing thoroughly, there's plenty to test. – Dan Puzey Apr 24 '12 at 14:58
0

RavenDB is specifically designed so that you don't need to mock everything for unit testing.

Just run it in-memory and you can then perform you unit tests against it directly. See this blog post for more info.

It lets you write code like this:

[Fact]
public void CanQueryForDistinctItemsUsingLinq()
{
    using (var store = NewDocumentStore())
    {
        using (var s = store.OpenSession())
        {
            s.Store(new { Name = "ayende" });
            s.Store(new { Name = "ayende" });
            s.Store(new { Name = "rahien" });
            s.SaveChanges();
        }

        store.DocumentDatabase.PutIndex("test", new IndexDefinition
        {
            Map = "from doc in docs select new { doc.Name }",
            Stores = { { "Name", FieldStorage.Yes } }
        });

        using (var s = store.OpenSession())
        {
            var objects = s.Query<User>("test")
                .Customize(x => x.WaitForNonStaleResults())
                .Select(o => new {o.Name })
                .Distinct()
                .ToList();

            Assert.Equal(2, objects.Count);
            Assert.Equal("ayende", objects[0].Name);
            Assert.Equal("rahien", objects[1].Name);
        }
    }
}

This comes from RavenDB unit/integration tests, so you'll need some infasctucture to get it working, but it gives the general idea.

Matt Warren
  • 10,279
  • 7
  • 48
  • 63
  • Yeah, but why bother setting up mocks, expectation etc to write a unit test, when you can write an integration test that actually tests the entire things (controller, dbase etc)? – Matt Warren Apr 24 '12 at 20:20
  • Not sure if in memory means raven simply runs a fake DB in memory. A unit test should mock all external layers but as soon as you are writing data into a database, memory or other data storage I would consider that not a unit test anymore but an integration test. – Nope Apr 24 '12 at 20:21
  • @FrançoisWahl take a look at some of Ayende's blog posts for a much better explanation than I can give. See http://ayende.com/blog/153029/northwind-starter-kit-review-data-access-and-the-essence-of-needless-work-part-ii?key=01a97aa23ec049839c3fb2dd91421e61 and http://ayende.com/blog/153701/ask-ayende-life-without-repositories-are-they-worth-living for starters (there are others in the series) – Matt Warren Apr 24 '12 at 20:24
  • sorry had to reword my original comment. A unit-test tests a very specific and focused scenario usually against your business layer, ensuring a specific behaviour of your business logic is as expected. An integration-test tests that all dependencies work together and are most of the time also written against the business layer or even as far back as the UI layer (Controllers in MVC or Presenters in Asp.NET Web). They are both testing different things. – Nope Apr 24 '12 at 20:25
  • Mind you, if you decide to only write integration test and no unit test that is completely up to yourself. However, you then take the risk that if your integration tests are failing due to a broken dependency that none of your test will pass. While unit tests would continue passing as they only test your business logic having mocked any other dependency. What you decide to implement and test is up to yourself in the end. – Nope Apr 24 '12 at 20:27
  • I agree with you on the difference between unit-test and integration test. I guess I'm just saying that with RavenDB it's been made easy to do integration tests, so you don't have to do the whole mocking/repository/service thing, which is often done only for the purpose of making unit testing possible – Matt Warren Apr 24 '12 at 20:27
  • I read the original blog-post you linked and yes, it seems Raven made it easy for you not having to worry about it to much which is a nice feature. I still would in addition add some unit tests I suppose. Again, that is just my own preference to have both. – Nope Apr 24 '12 at 20:29
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/10446/discussion-between-francois-wahl-and-matt-warren) – Nope Apr 24 '12 at 20:31