0

I have 3 layers in Asp.Net Web API. The controller layer, service layer and repository layer implemented using EF.

I am new to unit testing and have a simple function that gets a person by their id in the database and nothing else.

Basically the service layer calls

Unit_Work.Person_Repository.GetPersonByID(id);

and the Repository does this:

return context.chapters.Where(p=>p.chapterID==id).SingleOrDefault();
  1. What kind of Unit Test would i write on this.
  2. should i use the database or a mock implementation.
  3. I thought of using Sql Server Compact populating it with a mock person and then trying to get that person by ID is this correct.?

Thanks in advance to all those that answer.

DevTeamExpress
  • 183
  • 2
  • 9

3 Answers3

0

If you are using entity framework you can't unit test your data access layer.

Solution provided by Erik Alsmyr is very wrong! Look here why - What's the point of in memory IDbSet?.

When you use in memory db sets you are running Linq to Objects. When you use EF's DbContext your Linq is converted to SQL. Those are two different things!

It is very easy to write code that will work with in memory db set (all your unit tests will pass and you will be happy) just to notice runtime error first time you try to hit database.

Let's modify this code a bit. I don't think FULLNAME should have setter if we are using FIRSTNAME, LASTNAME. It should be calculated from FIRSTNAME and LASTNAME.

class User
{
    public string FIRSTNAME { get; set; }
    public string LASTNAME { get; set; }
    public string FULLNAME
    {
        get { return string.Format("{0}, {1}", LASTNAME, FIRSTNAME }
    }

    User(string firstName, string lastName)
    {
        this.FIRSTNAME = firstName;
        this.LASTNAME = lastName;
    }
}

Now you can write test like this and it will pass (of course after you implement it in controller)

public IMyEntities GetRepoWithUsers(params User[] users)
{
    var inMemoryUsers = new InMemoryDbSet<User>();
    var mockData = new Mock<IMyEntities>();
    mockData.Setup(m => m.Users).Returns(inMemoryUsers);
    return mockData.Object;      
}
[Test]
public void GetUserByFullname()
{          
    var ankaArne = new User("Arne", "Anka");
    var bjornBertil = new User("Bertil", "Björn");
    var repo = GetRepoWithUsers(ankaArne, bjornBertil);

    var usersController = new UsersController(repo);

    var found = usersController.GetUser("Anka, Arne");     

    Assert.NotNull(found);
    Assert.AreEqual("Anka", found.LASTNAME);
    Assert.AreEqual("Arne", found.FIRSTNAME);
}

But when you run it against 'real' DbContext and 'real' DbSet it will throw because you can't do Linq queries on calculated properties. Only on those that are mapped to database columns. So what's the point of that test?

Community
  • 1
  • 1
Piotr Perak
  • 10,718
  • 9
  • 49
  • 86
-1

You can use the xml/ .csv file for data. ie, you need to fetch the ID, chapter details from the xml file inside the unit test project. Then you have to pass the id as the parameter then check the return values with the data fetch from xml file. if you dont understand let me know. You cn create unit test project by add-new project options. then on vs2010 ther r options to add xml file for fetching the data to be tested.

your 3rd question is also correct. u cn populate the data from database and check the data with the return value

felix Antony
  • 1,450
  • 14
  • 28
-1

I recommend mocking and injecting an Entity framework context into your repository.

We do this using something similar to http://nuget.org/packages/FakeDbSet/

Then our unit tests look like this:

[TestFixture]
class UsersControllerTester
{
    private Mock<IMyEntities> mockData = null;

    [SetUp]
    public void Setup()
    {
        // Create fake data            
        var inMemoryUsers = new InMemoryDbSet<User>();
        inMemoryUsers.Add(new User { ID = 1, FIRSTNAME = "Arne", LASTNAME = "Anka", EMAIL = "arne.anka@email.com", FULLNAME = "Anka, Arne", USERNAME = "arne.anka" });
        inMemoryUsers.Add(new User { ID = 2, FIRSTNAME = "Bertil", LASTNAME = "Björn", EMAIL = "bertil.bjorn@email.com", FULLNAME = "Björn, Bertil", USERNAME = "bertil.bjorn" });
        inMemoryUsers.Add(new User { ID = 3, FIRSTNAME = "Carl", LASTNAME = "Cool", EMAIL = "carl.cool@email.com", FULLNAME = "Cool, Carl", USERNAME = "carl.cool" });
        inMemoryUsers.Add(new User { ID = 4, FIRSTNAME = "David", LASTNAME = "Dûsk", EMAIL = "david.dusk@email.com", FULLNAME = "Dûsk, David", USERNAME = "david.dusk" });

        // Create mock unit of work
        mockData = new Mock<IMyEntities>();
        mockData.Setup(m => m.Users).Returns(inMemoryUsers);      
    }

    [Test]
    public void GetUser()
    {           
        // Test
        var usersController = new UsersController(mockData.Object);

        // Invoke
        User user1 = usersController.GetUser("1");     

        // Assert
        Assert.NotNull(user1);
        Assert.AreEqual(1, user1.ID);
        Assert.AreEqual("Anka", user1.LASTNAME);
    }
Erik Alsmyr
  • 127
  • 5