简单EF函数的单元测试.net



我在Asp中有3个图层。Net Web API。控制器层、服务层和存储库层使用EF实现。

我是新的单元测试,并有一个简单的函数,通过他们的id在数据库中获得一个人,没有别的。

基本上服务层调用

Unit_Work.Person_Repository.GetPersonByID(id);

,并且Repository会这样做:

return context.chapters.Where(p=>p.chapterID==id).SingleOrDefault();
    我该写什么样的单元测试呢?
  1. 我应该使用数据库还是模拟实现。
  2. 我想到使用Sql Server Compact填充它与一个模拟的人,然后试图通过ID得到那个人是正确的。

提前感谢所有回答的人。

如果你使用实体框架,你不能单元测试你的数据访问层

Erik Alsmyr提供的解决方案是非常错误的!看这里为什么-内存中的IDbSet有什么意义?

当你使用内存数据库集时,你正在运行Linq to Objects。当您使用EF的DbContext时,您的Linq被转换为SQL。这是两码事!

这是很容易编写的代码,将工作在内存db集(你所有的单元测试将通过,你会很高兴),只是注意到运行时错误,你第一次尝试访问数据库。

让我们稍微修改一下代码。我认为FULLNAME不应该有setter如果我们使用FIRSTNAME LASTNAME。它应该从FIRSTNAME和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;
    }
}

现在你可以编写这样的测试,它将通过(当然在你在控制器中实现它之后)

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);
}

但是当你对'real' DbContext和'real' DbSet运行时,它会抛出,因为你不能对计算属性进行Linq查询。仅对那些映射到数据库列的。那么这个测试的意义是什么呢?

可以使用xml/.csv文件作为数据。即,您需要从单元测试项目中的xml文件中获取ID、章节详细信息。然后,您必须将id作为参数传递,然后使用从xml文件中获取的数据检查返回值。如果你不明白,让我知道。您可以通过添加新项目选项来创建单元测试项目。然后在vs2010上,有r选项添加XML文件来获取要测试的数据。

你的第三个问题也是正确的。您可以从数据库中填充数据,并使用返回值
检查数据。

我建议mock并将Entity框架上下文注入到您的存储库中。

我们使用类似于http://nuget.org/packages/FakeDbSet/

的东西来做这件事

然后我们的单元测试看起来像这样:

[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);
    }

最新更新