我是两个库的新手,在承诺在大型项目中使用之前,我需要澄清我在单元测试中使用低代码工作量自动插件的选项。
在谷歌上花了一些时间之后我得出结论,与其他一些IOC / Mocking产品配对不同,LightInject + Nsubstitute没有现成的插件库来简化在安排阶段的无操作默认模拟的声明单元测试。
我已经阅读了关于如何使用临时增强型模拟对象覆盖LightInject容器的LightInject文档,仅用于单元测试的范围但是单元测试可能触摸的所有无操作默认隔离模拟怎么办? 。有没有办法在LightInject容器中自动创建它们?
我正在寻找的内部IOC容器行为是:
public class LightInject.ServiceContainer
{
..
public T GetInstance<T)
{
if (( this.RegisteredInterfaces.Any( i => i.Itype == T ) == false )
&& ( this.TemporaryUnitTestOverrides.Any( i => i.Itype == T ) == false ))
&& ( /* this container is configured with an automocking delegate */ ))
return autoMockCreatorDelegate<T>.Invoke();
}
似乎LightInject的IProxy和Interceptors提供了一些内部模拟对象构建块,但是Nsubstitute库是完整的功能。
澄清我默认的意思是不做任何模拟和增强模拟。
// default do nothing mock
var calculator = Substitute.For<ICalculator>();
// Enhanced mock that will return 3 for .Add(1,2)
var calculator = Substitute.For<ICalculator>();
calculator.Add(1, 2).Returns(3);
显然,第二种增强型模拟需要在每个单元测试中本地制作。
答案 0 :(得分:8)
我是LightInject的作者,非常想帮助你。
让我看看这个并回复你。同时你可能想看看这个库 LightInject.AutopMoq这是对LightInject容器的第三方贡献。它使用Moq而不是NSubstitute,但一般概念应该与您要求的类似。
话虽这么说,我前段时间做了一些工作,进一步简化了自动锁定,并将对其进行了研究,看看它如何与NSubstitute集成。
修改
这是一个超级简单的自动锁定实现,适用于任何&#34;替换&#34;框架。
using System.Diagnostics;
using LightInject;
using NSubstitute;
public interface IFoo { }
class Program
{
static void Main(string[] args)
{
var serviceContainer = new ServiceContainer();
serviceContainer.RegisterFallback((type, s) => true, request => CreateMock(request.ServiceType));
var foo = serviceContainer.GetInstance<IFoo>();
Debug.Assert(foo is IFoo);
}
private static object CreateMock(Type serviceType)
{
return Substitute.For(new Type[] { serviceType }, null);
}
}
祝你好运
Bernhard Richter
答案 1 :(得分:1)
我对已接受答案的评论中承诺的一些反馈。我应用了LightInject的作者的建议,并成功地进行了一些简单的单元测试。
在完成基础工作后,我决定隐藏基类中的Ioc服务模拟设置代码以及我称之为MockingContext的内容,最终结果是更清晰的单元测试代码。模拟上下文类还确保将foreach Nsubstitute配置的模拟类型作为短期自动插件覆盖传递给Ioc服务,并且存在匹配的LightInjet.Service.EndMocking(T)调用。这消除了配置的模拟可能污染后续单元测试的自动模拟假设的危险。
在示例中,ClassC依赖于IFooA和IFooB(没有构造函数注入)。对于下面的单元测试,IFooA由LightInject自动模拟而没有显式代码,而IFooB通过Nsubstitute调用配置,并且还传递给MockingContext.Add&lt;&gt;()方法中的LightInject。
[TestClass]
public class UnitTest1 : AutoMocking
{
[TestMethod]
public void Test_1()
{
using (var mc = MockingContext)
{
// No need to mention IFooA here, LightInject will auto mock
// any interface not previously declared to it.
// Given
var mockB = mc.Add<IFooB>();
mockB.MethodY().Returns("Mock Value OOO");
var sut = new ClassC();
// When
var testResult = sut.MethodZ();
// Then
Assert.AreEqual(testResult, "MethodZ() received=Mock Value OOO");
}
}