如何在单元测试中模拟或替换 Entity Framework 上下文?
How to mock or substitute Entity Framework context in unit test?
我想在我的一个项目中对业务逻辑组件进行单元测试。
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() { ... }
}
Ninject配置:
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 配置时,它将被加载到内核中,但我想现在我误解了一些东西。你能帮我吗?
问题是您在 CommunicationService
构造函数中使用 NinjectConfig
而不是 FakeNinjectConfig
创建内核。
public class CommunicationService
{
IContext context;
public CommunicationService()
{
var kernel = new StandardKernel(new NinjectConfig());
context = kernel.Get<IContext>();
}
简单方法:
您可以创建一个新的构造函数来注入 NinjectModule
或 StandardKernel
.
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.
}
我想在我的一个项目中对业务逻辑组件进行单元测试。
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() { ... }
}
Ninject配置:
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 配置时,它将被加载到内核中,但我想现在我误解了一些东西。你能帮我吗?
问题是您在 CommunicationService
构造函数中使用 NinjectConfig
而不是 FakeNinjectConfig
创建内核。
public class CommunicationService
{
IContext context;
public CommunicationService()
{
var kernel = new StandardKernel(new NinjectConfig());
context = kernel.Get<IContext>();
}
简单方法:
您可以创建一个新的构造函数来注入 NinjectModule
或 StandardKernel
.
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.
}