简体   繁体   English

单元测试异步数据库方法

[英]Unit testing async database methods

I have a Web API that I want to test using MS Test. 我有一个要使用MS Test测试的Web API。 I want to test one controller in particular. 我想特别测试一个控制器。 This is the init code: 这是初始化代码:

public class MyControllerTests
{
    private static MyController controller;

    [AssemblyInitialize]
    public static void Initialize(TestContext context)
    {
        controller = new MyController();

        IoC.Register(Component.For<IDbContextFactory>().ImplementedBy<MockDbContextFactory>());
        // other config
    }
    // test methods, all async
}

This is the mock context factory. 这是模拟上下文工厂。 Is it used inside all the API methods to get a DB context. 是否在所有API方法中使用它来获取数据库上下文。

public class MockDbContextFactory : IDbContextFactory
{
    MyContext context;

    public MyBaseContext GetContext()
    {
        if (context == null)
        {
            context = new MyContext(new DropCreateDatabaseAlways<MyContext>());

            //populate with mock data...
        }

        return context;
    }
}

Everything was nice until I added a test for the delete method. 一切都很好,直到我为delete方法添加了测试。 It is finished before the other methods, so it deletes objects from the shared context and the other tests fail. 它在其他方法之前完成,因此它从共享上下文中删除对象,其他测试失败。 No I have two ideas: new context per method (using a [TestInitialize] resetter), but the underlying database is still the same and I get lots of key conflicts when inserting the new mock objects. 不,我有两个想法:每个方法都有新的上下文(使用[TestInitialize]重置程序),但是底层数据库仍然相同,并且在插入新的模拟对象时会遇到很多键冲突。 Another idea is setting a new database in memory and having completely separate instances. 另一个想法是在内存中设置一个新数据库并具有完全独立的实例。 I found Effort , but I believe this is an overkill and I'm approaching it wrong. 我找到了Effort ,但是我认为这是一个过大的杀伤力,我正在错误地解决它。

I am using Castle Windsor as the IoC container, in case there is a way to do it on the IoC level. 我使用Castle Windsor作为IoC容器,以防万一可以在IoC级别上做到这一点。

I think you might be looking at this the wrong way. 我认为您可能会以错误的方式看待这个问题。

The purpose of a unit test is to test a unit of functionality that is isolated from any other unit. 单元测试的目的是测试与任何其他单元隔离的功能单元。 There is no need to Unit Test Entity Framework, it's been thoroughly tested. 无需对单元测试实体框架进行全面测试。 Any time that you create a Test of a CRUD operation, you are really creating an Integration Test, not a Unit Test. 每当您创建CRUD操作的测试时,实际上就是在创建集成测试,而不是单元测试。

If you really need to test your CRUD operations, then your mock factory should just be returning successes for all the operations that are passed to it, or saving data locally to pass back for verification. 如果您确实需要测试CRUD操作,那么模拟工厂应该只是返回传递给它的所有操作的成功,或者在本地保存数据以返回进行验证。 It shouldn't be creating a "test" DbContext object that still has to not only interact with a Database but also interact with your other tests. 它不应该创建一个“测试” DbContext对象,该对象不仅必须与数据库交互,而且还必须与您的其他测试交互。 Your unit test should be focused on verifying the operations in the function under test only. 您的单元测试应仅专注于验证被测函数中的操作。

Now, if your intent is to perform Integration Tests, then the normal practice would be for the test itself to insert the objects it is going to delete. 现在,如果您打算执行集成测试,那么通常的做法是让测试本身插入要删除的对象。 Having the delete test trying to delete records that were inserted by another test is always going to be a challenge for timing. 让删除测试尝试删除由另一个测试插入的记录始终是计时的挑战。 Plus, there is no reason to even worry about deleting objects inserted by your Insert tests, with DropCreateDatabaseAlways . 另外,甚至没有理由担心使用DropCreateDatabaseAlways删除通过插入测试插入的对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM