如何在单元测试中模拟或替换Entity Framework上下文?

时间:2016-03-23 16:19:07

标签: c# unit-testing mocking entity-framework-6 ninject

我想在我的一个项目中对业务逻辑组件进行单元测试。

BL:

public class CommunicationService
{
    IContext context;

    public CommunicationService()
    {
        var kernel = new StandardKernel(new NinjectConfig());
        context = kernel.Get<IContext>();
    }

    // This creates a file
    public void SomeMethodThatUsesIContext() { ... }
}

NinjectConfig:

class NinjectConfig : NinjectModule
{
    public override void Load()
    {
        Bind<IContext>().To<CommunicationDbContext>();
    }
}

单元测试:

[TestMethod]
public void ScheduleTransportOrder_1()
{
    communicationService = new CommunicationService();
    communicationService.SomeMethodThatUsesIContext();
    Assert.IsTrue(...) // file should be created.
}

我在单元测试的项目中有另一个Ninject配置:

class FakeNinjectConfig : NinjectModule
{
    public override void Load()
    {
        Bind<IContext>().To<FakeDbContext>();
    }
}

我希望在单元测试中使用IContext的这种实现。但它仍然使用原始的CommunicationDbContext实现。我相信,当我在这里有另一个ninject配置时,它将加载到内核,但我想我现在误解了一些东西。你能帮帮我吗?

1 个答案:

答案 0 :(得分:2)

问题是你在NinjectConfig构造函数中使用FakeNinjectConfig而不是CommunicationService创建内核。

public class CommunicationService
{
    IContext context;

    public CommunicationService()
    {
        var kernel = new StandardKernel(new NinjectConfig());
        context = kernel.Get<IContext>();
    }

简单方法:

您可以创建一个新的构造函数来注入NinjectModuleStandardKernel

public CommunicationService (StandardKernel kernel) 
{
    context = kernel.Get<IContext>();
}

public CommunicationService(NinjectModule injectModule):this (new StandardKernel(injectModule))
{
    context = kernel.Get<IContext>();
}

public CommunicationService():this (new NinjectConfig())
{}

在测试中,您可以使用FakeNinjectConfig调用构造函数。

[TestMethod]
public void ScheduleTransportOrder_1()
{
    communicationService = new CommunicationService(new FakeNinjectConfig ());
    communicationService.SomeMethodThatUsesIContext();
    Assert.IsTrue(...) // file should be created.
}

或者

[TestMethod]
public void ScheduleTransportOrder_1()
{
    communicationService = new CommunicationService(new StandardKernel(new FakeNinjectConfig ()));
    communicationService.SomeMethodThatUsesIContext();
    Assert.IsTrue(...) // file should be created.
}

正确方法:

但在我看来,您应该将IContext添加为依赖项并注入IContext解析CommunicationService

public class CommunicationService
{
    IContext context;

    public CommunicationService(IContext _context)
    {
       context = _context;
    }

然后,当您创建CommunicationService时,您应该使用Get内核方法而不是new运算符。例如,而不是 communicationService = new CommunicationService()您应该使用communicationService = Kernel.Get<CommunicationService>();

[TestMethod]
public void ScheduleTransportOrder_1()
{
    var testKernel = new StandardKernel(new FakeNinjectConfig ());
    communicationService = testKernel.Get<CommunicationService>();
    communicationService.SomeMethodThatUsesIContext();
    Assert.IsTrue(...) // file should be created.
}

或者您可以直接注入IContext

[TestMethod]
public void ScheduleTransportOrder_1()
{
    communicationService = new CommunicationService(new FakeDbContext());
    communicationService.SomeMethodThatUsesIContext();
    Assert.IsTrue(...) // file should be created.
}