ASP.NET 系列:單元測試之StructureMap

剛哥521發表於2016-02-05

ASP.NET使用StructureMap等依賴注入元件時最重要就是EntityFramework的DbContext物件要保證在每次HttpRequest只有一個DbContext例項,這裡將使用第三方提供的HttpSimulator進行測試。

1.定義IDependency介面

建立遮蔽不同依賴注入元件使用差別的介面。

public interface IDependency
{
    void Build();

    void EndRequest();

    void AddTransient(Type from, Type to, object instance = null);

    void AddScoped(Type from, Type to, object instance = null);

    void AddSingleton(Type from, Type to, object instance = null);

    object GetInstance(Type type);

    IEnumerable GetAllInstances(Type type);
}

2.提供StructureMap的適配類StructureMapAdapter

public class StructureMapAdapter : IDependency, IDisposable
{
    private bool _disposed = false;
    private Container _container;
    private Registry _registry;

    public StructureMapAdapter()
    {
        this._registry = new Registry();
    }

    public void Build()
    {
        _container = new Container(_registry);
    }

    public void EndRequest()
    {
        HttpContextLifecycle.DisposeAndClearAll();
    }

    public void AddTransient(Type from, Type to, object instance = null)
    {
        if (instance == null)
        {
            _registry.For(from).Use(to).LifecycleIs<TransientLifecycle>();
        }
        else
        {
            _registry.For(from).Use(instance).LifecycleIs<TransientLifecycle>();
        }
    }

    public void AddScoped(Type from, Type to, object instance = null)
    {
        if (instance == null)
        {
            _registry.For(from).Use(to).LifecycleIs<HttpContextLifecycle>();
        }
        else
        {
            _registry.For(from).Use(instance).LifecycleIs<HttpContextLifecycle>();
        }
    }

    public void AddSingleton(Type from, Type to, object instance = null)
    {
        if (instance == null)
        {
            _registry.For(from).Use(to).LifecycleIs<SingletonLifecycle>();
        }
        else
        {
            _registry.For(from).Use(instance).LifecycleIs<SingletonLifecycle>();
        }
    }

    public object GetInstance(Type type)
    {
        return _container.GetInstance(type);
    }

    public IEnumerable GetAllInstances(Type type)
    {
        return _container.GetAllInstances(type);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                this._container.Dispose();
            }

            _disposed = true;
        }
    }
}

3.使用HttpSimulator進行單元測試

public class StructureMapAdapterTest
{
    [Fact]
    public void TransientTest()
    {
        IDependency dependency = new StructureMapAdapter();
        dependency.AddTransient(typeof(ITest), typeof(Test));
        dependency.Build();
        var version1 = ((ITest)dependency.GetInstance(typeof(ITest))).Version;
        var version2 = ((ITest)dependency.GetInstance(typeof(ITest))).Version;
        Assert.NotEqual(version1, version2);
    }

    [Fact]
    public void SingletonTest()
    {
        IDependency dependency = new StructureMapAdapter();
        dependency.AddSingleton(typeof(ITest), typeof(Test));
        dependency.Build();
        var version1 = ((ITest)dependency.GetInstance(typeof(ITest))).Version;
        var version2 = ((ITest)dependency.GetInstance(typeof(ITest))).Version;
        Assert.Equal(version1, version2);
    }

    [Fact]
    public void ScopedTest()
    {
        var version1 = "";
        var version2 = "";
        using (HttpSimulator simulator = new HttpSimulator())
        {
            IDependency dependency = new StructureMapAdapter();
            dependency.AddScoped(typeof(ITest), typeof(Test));
            dependency.Build();
            simulator.SimulateRequest(new Uri("http://localhost/"));
            version1 = ((ITest)dependency.GetInstance(typeof(ITest))).Version;
            version2 = ((ITest)dependency.GetInstance(typeof(ITest))).Version;
            Assert.Equal(version1, version2);
        }

        using (HttpSimulator simulator = new HttpSimulator())
        {
            IDependency dependency = new StructureMapAdapter();
            dependency.AddScoped(typeof(ITest), typeof(Test));
            dependency.Build();
            simulator.SimulateRequest(new Uri("http://localhost/"));
            version1 = ((ITest)dependency.GetInstance(typeof(ITest))).Version;
        }
        using (HttpSimulator simulator = new HttpSimulator())
        {
            IDependency dependency = new StructureMapAdapter();
            dependency.AddScoped(typeof(ITest), typeof(Test));
            dependency.Build();
            simulator.SimulateRequest(new Uri("http://localhost/"));
            version2 = ((ITest)dependency.GetInstance(typeof(ITest))).Version;
        }
        Assert.NotEqual(version1, version2);
    }
}

public interface ITest
{
    String Version { get; }
}

public class Test : ITest
{
    private string _version = Guid.NewGuid().ToString();

    public string Version { get { return this._version; } }
}

執行結果:

相關文章