单元测试存储库

时间:2012-01-13 01:12:53

标签: asp.net-mvc entity-framework repository-pattern

在我的项目中,我遵循Repository Pattern。我的存储库与持久层对话,我使用实体框架作为ORM。

目前,在我的单元测试中,我直接针对持久层进行编码,因此任何测试都直接针对数据库运行。因此,如果我测试插入,它实际上会将数据插入数据库。

我想知道如何测试而不必担心数据库被修改?

我有办法进行内存数据库测试吗?

由于

我在App_Data中创建了一个类似于实际的数据库模式,然后我尝试像这样实现它 -

    [TestInitialize]
    public void TestInitialize()
    {

        //TODO:  in TestCleanup, do a rollback to revert any changes performed during the test.
        Database.SetInitializer<LogViewerDbContextFake>(new LogViewerInitializer());
    }

    [TestMethod]
    public void Get_Should_Return_List_Of_Applications()
    {
        // Arrange
        LogViewerDbContext testDbContext = new LogViewerDbContextFake();
        ApplicationRepository sut = new ApplicationRepositoryImpl(testDbContext);

        // Act
        List<string> failure = sut.Get();

        // Assert
        Assert.AreEqual(4, failure.Count);
    }

 internal class LogViewerInitializer : DropCreateDatabaseIfModelChanges<LogViewerDbContextFake>
{
    protected override void Seed(LogViewerDbContextFake context)
    {
        List<LogEntry> logEntries = new List<LogEntry>()
        {
            new LogEntry{
                Id = 1,
                Application = "Application 1"
            },
            new LogEntry{
                Id = 2,
                Application = "Application 2"
            },
            new LogEntry{
                Id = 3,
                Application = "Application 3"
            },
            new LogEntry{
                Id = 4,
                Application = "Application 4"
            },
            new LogEntry{
                Id = 5,
                Application = "Application 2"
            },
            new LogEntry{
                Id = 6,
                Application = "Application 2"
            }
        };

        logEntries.ForEach(s => context.LogEntries.Add(s));
        context.SaveChanges();
    }
}

即使测试运行并通过,LogViewerInitializer也没有在App_Data \ Database中插入任何记录。所以,我想知道背后的逻辑是什么以及事情究竟是如何被执行的?

3 个答案:

答案 0 :(得分:1)

使用TransactionScope块来避免将数据提交到数据库。

using (TransactionScope scope = new TransactionScope())
{
     // test goes here

     db.SaveChanges();

    // assertions    
}

答案 1 :(得分:0)

您是否尝试过使用像Rhinomocks或MOQ这样的模拟框架来模拟持久层?

或者,您可以提出您实际上正在进行端到端测试的参数,并在运行测试后从数据库中删除数据。您可以通过在使用属性运行测试之前和之后运行post和pre sql脚本来完成此操作。如果您使用的是PostSharp等AOP框架,这将非常简单。如果没有,你仍然可以使用contextbound对象来完成它,正如我已经解释过here

答案 2 :(得分:0)

我使用ninject和EF构建了自己的存储库框架。如果您有兴趣,请看一下这里,我还有一个如何使用我的存储库框架来生成简单单元测试的示例。

http://blog.staticvoid.co.nz/2011/10/staticvoid-repository-pattern-nuget.html