0

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

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

    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 定义为类变量,而不是在每个方法中创建新实例?

4

2 回答 2

1

你有一个正确的总体思路。您的 MockInsert方法应该将实体保存到某个内存存储中,以便后续查询将返回插入的信息,正如预期的那样。但是拥有一个具有“真实”和“模拟”实现的接口的非常基本的想法就在那里。

请记住,在测试中使用 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。

于 2012-09-05T09:50:58.233 回答
1

是的。我唯一要避免的是创建一个实际的模拟类(在这种情况下,它应该称为 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/

于 2012-09-05T10:07:34.713 回答