单元测试一个使用linq-to-sql的类



我想为一个包含linq-sql代码的类编写单元测试。我的意思是,在每个方法中,我都创建了一个新的DbContext并完成了数据库工作。

我在网上搜索了一下。首先我开始使用存储库和工作单元模式,但我发现DbContext本身是一个工作单元,它的dbset作为存储库工作。另一点是,我认为没有必要测试Linq部分,因为它可以正常工作(由.net团队测试)。我想测试我添加到代码中的逻辑。所以我决定用两个实现创建一个带有必要方法的接口,一个使用linqToSql,而另一个只是一个mock。像这样的东西:

    public interface IDbManager
    {
        bool Insert(MyEntity newEntity);
    }
    public class RealDbManager:IDbManager
    {
        public bool Insert(MyEntity newEntity)
        {
            using (DbDataContext db = new DbDataContext())
            {
                db.MyEntities.InsertOnSubmit(newEntity);
                db.SubmitChanges();
            }
        }
    }
    public class MockDbManager:IDbManager
    {
        public bool Insert(MyEntity newEntity)
        {
            return true;
        }
    }

整个想法正确吗?如果是,这是一个正确的实现吗?

是否可以将DbDataContext定义为类变量,而不是在每个方法中创建新实例?

您已经有了正确的总体思路。Mock Insert方法应该将实体保存到内存中的某个存储中,以便后续查询将返回插入的信息,正如预期的那样。但是,有一个接口的基本思想,一个"真实"和一个"模拟"实现是存在的。

请记住,在测试中使用Mock时,您正在测试使用Mock的其他代码,而不是Mock本身。

至于将DataContext定义为成员变量;你可以使用一个IDisposable模式,比如:

public class RealDbManager:IDbManager, IDisposable
{
    DbDataContext db = new DbDataContext();
    public bool Insert(MyEntity newEntity)
    {
        {
            db.MyEntities.InsertOnSubmit(newEntity);
            db.SubmitChanges();
        }
    }
    public void Dispose()
    {
        db.Dispose();
    }
}

那么,你只需要确保处理掉你的DbManager。

是。我唯一要避免的是创建一个实际的模拟类(在这种情况下,它应该被称为Fake),但要使用模拟引擎。

在你的问题中,你提到了两种测试。首先是测试类的行为,其次是测试它的集成。它们看起来是一样的,但事实并非如此。

首先,你需要模拟你的类,以这种方式(使用Moq)测试它与其他类的"连接":

  [Test]
  public void Test()
  {
       var entity = new Entity();
       var mocked = new Mock<IDbManager>();
       //you are telling the moq engine everytimes it finds an invocation of your repository
       //to return true as you did in you mocked class
       mocked.Setup( x => x.Insert( entity ) ).Returns( true );
       var classUnderTest = new ClassUnderTest( mocked.Object );
       //in this method you invoke your repository
       var ret = classUnderTest.DoSomething( entity );
       //assertions
       Assert.Equal( something, ret);
      //eventually you can verify that your repository has been hit once
      mocked.Verify( x => x.Insert( It.IsAny<Entity>), Times.Once);
  }

稍后,正如您正确指出的那样,您在linq上没有什么可测试的(微软为我们做了这件事),但如果您需要验证linq的正确性,您只能针对真实的数据库(或使用存储库模式针对伪造的存储库)进行测试。这是一个集成测试,它与嘲讽无关。

若要将类与DbContext解耦,可以使用存储库模式。看看这篇文章。http://dotnetspeak.com/index.php/2011/03/repository-pattern-with-entity-framework/

最新更新