简体   繁体   English

使用NSubstitute(或其他方法)进行Unity和自动模拟

[英]Unity and auto-mocking with NSubstitute (or something else)

My question derives from this question: Is this possible with Unity (Instead of Castle Windsor)? 我的问题来自于这个问题: Unity(代替温莎城堡)有可能吗?

Here is the class from the answer: 这是答案中的课程:

protected override void Initialize()
{
    var strategy = new AutoMockingBuilderStrategy(Container);

    Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);
}

class AutoMockingBuilderStrategy : BuilderStrategy
{
    private readonly IUnityContainer container;
    private readonly Dictionary<Type, object> substitutes 
       = new Dictionary<Type, object>();

    public AutoMockingBuilderStrategy(IUnityContainer container)
    {
        this.container = container;
    }

    public override void PreBuildUp(IBuilderContext context)
    {
        var key = context.OriginalBuildKey;

        if (key.Type.IsInterface && !container.IsRegistered(key.Type))
        {
            context.Existing = GetOrCreateSubstitute(key.Type);
            context.BuildComplete = true;
        }
    }

    private object GetOrCreateSubstitute(Type type)
    {
        if (substitutes.ContainsKey(type))
            return substitutes[type];

        var substitute = Substitute.For(new[] {type}, null);

        substitutes.Add(type, substitute);

        return substitute;
    }
}

The posted solution there works well for a SINGLE object. 在那里发布的解决方案对于单个对象非常适用。 If you see the solution posted, it will return the same object everytime I call Resolve 如果看到发布的解决方案,则每次调用Resolve时,它将返回相同的对象

This is fine in a test case like the following: 在如下所示的测试用例中可以这样做:

var myObjectWithInnerMockedObjects = UnityContainer.Resolve<ISomeInterface>();
var internalAutoMockedObject = UnityContainer.Resolve<IInnerInterface>();

The solution posted in the said question works well for above. 在上述问题中发布的解决方案在上述情况下效果很好。

The above code creates an object via Unity and tries to resolve the constructor arguments and if the type is not mapped in unity config, returns a mock via NSubstitute. 上面的代码通过Unity创建一个对象,并尝试解析构造函数参数,如果该类型未在unity config中映射,则通过NSubstitute返回一个模拟。

So effectively the chain could be: 因此,有效的链条可以是:

- ActualObject
    - InnerActualObjectDependency
        - MockedDependency (since this was not mapped in Unity, a mock was created)

Problem is if I create 2 of such objects, the mocks point to the same object. 问题是如果我创建2个此类对象,则模拟指向相同的对象。

If I remove the CONTAINS check, in method GetOrCreateSubstitute(), then I get a new mock every time... But then how do I access a particular object's mock to set expectations on it? 如果我在GetOrCreateSubstitute()方法中取消了CONTAINS检查,那么每次都会得到一个新的模拟...但是,如何访问特定对象的模拟以对其设置期望呢? :-( :-(

I hope I am clear with the question!! 我希望我对这个问题很清楚!

We had an internal team discussion and I understood better that mocks are meant to be singleton. 我们有一个内部团队讨论,我更好地理解嘲笑的意思是单身。 By design we do not want a different mock object for every created object. 通过设计,我们不希望为每个创建的对象都使用不同的模拟对象。

A mock is for a class and not for methods. 模拟是针对类而非方法的。 So the following pseudo-code would be the perfect way to achieve what I am doing. 因此,以下伪代码将是实现我正在做的事情的完美方法。

var obj1 = Resolve<IMyInterface>();
var obj2 = Resolve<IMyInterface>();
var innerDependency = Resolve<IInnerType>(); // Returns the same object that is shared by above 2 objs

innerDependency.SetExpection(Some expectation);
obj1.PerformAction();
innerDependency.Assert();

innerDependency.SetExpection(Some *different* expectation);
obj2.PerformAction();
innerDependency.Assert();

So The very pretext of the question is faulty. 因此,这个问题的借口是错误的。 We do not have such flexibility because we do not want to! 我们没有这种灵活性,因为我们不想这样做!

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

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