2

私は現在、Unity と NSubstitute を使用して、DI とモッキングを学ぼうとしています。私はまた、この質問から取られた自動モック拡張機能を使用しています:これは Unity (Castle Windsor の代わりに) で可能ですか?

以下の単体テストでは、メソッド Add() から NSubstitute の戻り値 10 を設定しようとしています。ただし、コントローラー呼び出しを介してデバッグする場合、割り当てられた値は、予想される 10 ではなくデフォルトの 0 です。プロキシはメソッド呼び出しをインターセプトしていないようです。

これは、タイプ/コンテナを正しく登録していないことが原因であると思われます。誰かが私を正しい方向に向けることができますか?

[TestFixture]
public class ApplicationControllerTests
{
    private IUnityContainer _container;
    private ApplicationController _controller;
    private ISampleService _sampleService;

    [SetUp]
    public void SetUp()
    {
        _container = new UnityContainer().AddExtension(new AutoMockingContainerExtension());
        _controller = _container.Resolve<ApplicationController>();
        _sampleService = _container.Resolve<ISampleService>();
    }

    [Test]
    public void TestSampleService()
    {
        // This line is not working
        _sampleService.Add(Arg.Any<int>(), Arg.Any<int>()).Returns(10);

        var result = _controller.Index();

        _sampleService.Received().Add(Arg.Any<int>(), Arg.Any<int>());
    }
}

public class AutoMockingContainerExtension : UnityContainerExtension
{
    protected override void Initialize()
    {
        var strategy = new AutoMockingBuilderStrategy(Container);

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

    class AutoMockingBuilderStrategy : BuilderStrategy
    {
        private readonly IUnityContainer _container;

        public AutoMockingBuilderStrategy(IUnityContainer container)
        {
            _container = container;
        }

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

            if (key.Type.IsInterface && !_container.IsRegistered(key.Type))
                context.Existing = CreateSubstitute(key.Type);
        }

        private static object CreateSubstitute(Type type)
        {
            return Substitute.For(new[] { type }, null);
        }
    }
}

そして私のコントローラーコード

public class ApplicationController : BaseController
{
    private readonly ISampleService _sampleService;

    public ApplicationController(ISampleService sampleService)
    {
        _sampleService = sampleService;
    }

    public ActionResult Index()
    {
        var result = _sampleService.Add(2, 3);

        // result is 0, expected 10 ??

        return View();
    }
}

public interface ISampleService
{
    int Add(int first, int second);
}

public class SampleService : ISampleService
{
    public int Add(int first, int second)
    {
        return first + second;
    }
}
4

2 に答える 2

4

実際、Tormod は正しく、誰かがコンテナーから要求するAutoMockingBuilderStrategy たびに異なるモック インスタンスを返すという問題があります。ISampleService

したがって、私の元の実装にはバグがあります。つまりAutoMockingBuilderStrategy、作成されたモックが保存されません。

修正版は次のとおりです。

public class AutoMockingContainerExtension : UnityContainerExtension
{
    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;
        }
    }
}
于 2012-11-14T06:23:27.913 に答える
1

セットアップの 2 行目と 3 行目でそれぞれ作成された ISampleService の 2 つの異なるインスタンスを扱っているのではないかと思います。テストのために、_sampleServie フィールドを public にして、3 番目の Setup() 行で試していただけますか

_sampleService = _controller._sampleService;
于 2012-11-14T06:11:47.417 に答える