asp.net核心数据库集成测试

时间:2018-05-09 13:52:56

标签: c# database integration-testing

我正在尝试在asp.netcore项目中设置数据库的集成测试。我使用代码第一种方法来创建数据库 对于测试iam使用nudget包XUnit,FluentAssertions和NUnitestApadter3。 当我第一次运行测试时,测试通过了。

[Collection("Integration test collection")]
public class BookServiceTest : IntegrationTestBase
{
    [Fact]
    public void CanCreateUser()
    {
        using (var context = GivenBPDContext())
        {
            var Book = new BookService(context);

            Data.Database.Entities.Book book = Book.AddNewBook("test");
            context.SaveChanges();

            book.Id.Should().NotBe(0);
            book.Name.Should().Be("test");
        }
    }
}

public class IntegrationTestBase
{
    protected static BPDContext GivenBPDContext()
    {

        var context = new BPDContext(new DbContextOptionsBuilder().Options);

        return context;
    }
    // i tried dropping the database here and it do not work
}

一个非常基本的逻辑测试

public class BookService
{
    private BPDContext _context;

    public BookService(BPDContext context)
    {
        _context = context;
    }

    public Book AddNewBook(string name)
    {
        var book = _context.Books
            .FirstOrDefault(x => x.Name == name);

        if (book == null)
        {
            book = _context.Books.Add(new Data.Database.Entities.Book
            {
                Name = name,
            }).Entity;
        }

        return book;
    }
}

第二次运行测试并更改正在测试的值时,它失败了。我需要一种方法在每次测试后删除数据库然后运行 迁移以使数据库达到正确的版本。

以下是我如何设置数据库。 startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddTransient<IBPDRepository, BPDRepository>();
    services.AddDbContext<BPDContext>();
}

public class BPDContext:DbContext
{
    public DbSet<Entities.Book> Books { get; set; }
    public DbSet<Entities.User> User { get; set; }
    public DbSet<Entities.Reviewer> Reviewer { get; set; }

    public BPDContext(DbContextOptions options):base(options)
    {

    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        //maybe put something in if its in testing mode
        optionsBuilder.UseSqlServer("Server = (localdb)\\mssqllocaldb;Database = BookProjectDatabase;Trusted_Connection = True; ", options => options.MaxBatchSize(30));
        optionsBuilder.EnableSensitiveDataLogging();
    }

}

总之,我需要在每次测试运行之前删除数据库,然后使用迁移更新数据库,最后执行单元。

2 个答案:

答案 0 :(得分:3)

看看Respawn。避免迁移的另一个选择是执行数据库快照/还原。最后,您可以在每次测试之前启动新的TransactionScope,然后在事务之后调用其Dispose()方法,而不调用其Complete()方法。这将中止事务并将数据库回滚到运行测试之前的状态。

删除数据库有点笨拙,可能会增加运行测试所需的时间。

答案 1 :(得分:1)

您可以使用InMemoryDbContext进行测试操作。通过InMemoryDbContext,您不必创建物理数据库;此外,您可以轻松处理它。

[Collection("Integration test collection")]
public class BookServiceTest : IDisposible
{
    private BDPContext _context;
    public BookServiceTest()
    {
        DbContextOptions<BPDContext> options = new DbContextOptionsBuilder<BPDContext>()
            .UseInMemoryDatabase(GetType().Name)
            .Options;

        _context = new BPDContext(options);
    }

    [Fact]
    public void CanCreateUser()
    {
        var Book = new BookService(context);

        Data.Database.Entities.Book book = Book.AddNewBook("test");
        context.SaveChanges();

        book.Id.Should().NotBe(0);
        book.Name.Should().Be("test");
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

你想用真正的db(集成测试)进行测试,修改你的测试可能很容易解决。

[Fact]
public void CanCreateUser()
{
    string bookName = DateTime.Now + "test book";
    var Book = new BookService(context);


    Data.Database.Entities.Book book = Book.AddNewBook(bookName);
    context.SaveChanges();

    book.Id.Should().NotBe(0);
    book.Name.Should().Be(bookName);
}