【问题标题】:How do you mock ServiceStack ISession using Moq and StructureMap?如何使用 Moq 和 StructureMap 模拟 ServiceStack ISession?
【发布时间】:2013-02-20 15:12:58
【问题描述】:

我正在使用 ServiceStack / StructureMap / Moq。该服务调用类型为 ServiceStack.CacheAccess.ISession 的 Session。对于单元测试,我使用 Moq 创建了一个 Mock 对象,并将其添加到 StructureMap 配置中:

protected Mock<ISession> sessionMock = new Mock<ISession>();
ObjectFactory.Configure(
    cfg =>
       {
           cfg.For<ISession>().Use(sessionMock.Object);

但是,当 Session 对象为空时,我并不感到惊讶——我很确定我遗漏了一步。我还需要做什么才能用模拟对象填充我的 Session 属性?

[编辑] 这是一个简单的测试场景

要测试的代码。简单的请求/服务

[Route("getKey/{key}")]
public class MyRequest:IReturn<string>
{
    public string Key { get; set; }
}

public class MyService:Service
{
    public string Get(MyRequest request)
    {
        return (string) Session[request.Key];
    }
}

基础测试类和 MockSession 类

// test base class
public abstract class MyTestBase : TestBase
{
    protected IRestClient Client { get; set; }

    protected override void Configure(Container container)
    {
        // this code is never reached under any of my scenarios below
        container.Adapter = new StructureMapContainerAdapter();
        ObjectFactory.Initialize(
            cfg =>
                {
                    cfg.For<ISession>().Singleton().Use<MockSession>();
                });
    }
}

public class MockSession : ISession
{
    private Dictionary<string, object> m_SessionStorage = new Dictionary<string, object>();

    public void Set<T>(string key, T value)
    {
        m_SessionStorage[key] = value;
    }

    public T Get<T>(string key)
    {
        return (T)m_SessionStorage[key];
    }

    public object this[string key]
    {
        get { return m_SessionStorage[key]; }
        set { m_SessionStorage[key] = value; }
    }
}

和测试。请参阅 cmets 了解我看到失败的地方。我真的不希望版本 1 和 2 能够工作,但希望版本 3 能够。

[TestFixture]
public class When_getting_a_session_value:MyTestBase
{
    [Test]
    public void Test_version_1()
    {
        var session = ObjectFactory.GetInstance<MockSession>();
        session["key1"] = "Test";
        var request = new MyRequest {Key = "key1"};
        var client = new MyService();  // generally works fine, except for things like Session
        var result = client.Get(request);  // throws NRE inside MyService
        result.ShouldEqual("Test");
    }

    [Test]
    public void Test_version_2()
    {
        var session = ObjectFactory.GetInstance<MockSession>();
        session["key1"] = "Test";
        var request = new MyRequest {Key = "key1"};
        var client = ObjectFactory.GetInstance<MyService>();
        var result = client.Get(request);  // throws NRE inside MyService
        result.ShouldEqual("Test");
    }
    [Test]
    public void Test_version_3()
    {
        var session = ObjectFactory.GetInstance<MockSession>();
        session["key1"] = "Test";
        var request = new MyRequest {Key = "key1"};
        var client = CreateNewRestClient();
        var result = client.Get(request);  // throws NotImplementedException here
        result.ShouldEqual("Test");
    }
}

【问题讨论】:

  • 我认为这是因为我在单元测试时没有正确配置 StructureMap 适配器。不知道该怎么做...
  • 你能展示所有的测试代码吗?也就是说,我们可以看到你是如何调用服务的?
  • 添加了显示问题以及我如何尝试解决问题的代码。

标签: moq structuremap servicestack


【解决方案1】:

看起来您正在尝试创建单元测试,但您使用的是 AppHost,就像您进行了集成测试一样。请参阅此previous answer for differences between the twodocs on Testing

您可以通过在Request.Items["__session"] 中注册一个实例来模拟会话,例如:

[Test]
public void Can_mock_IntegrationTest_Session_with_Request()
{
    using (new BasicAppHost(typeof(MyService).Assembly).Init())
    {
        var req = new MockHttpRequest();
        req.Items[SessionFeature.RequestItemsSessionKey] = 
            new AuthUserSession {
                UserName = "Mocked",
            };

        using (var service = HostContext.ResolveService<MyService>(req))
        {
            Assert.That(service.GetSession().UserName, Is.EqualTo("Mocked"));
        }
    }
}

否则,如果您设置AppHost.TestMode=true,ServiceStack 将返回在您的 IOC 中注册的IAuthSession,例如:

[Test]
public void Can_mock_UnitTest_Session_with_IOC()
{
    var appHost = new BasicAppHost
    {
        TestMode = true,
        ConfigureContainer = container =>
        {
            container.Register<IAuthSession>(c => new AuthUserSession {
                UserName = "Mocked",
            });
        }
    }.Init();

    var service = new MyService {
        Request = new MockHttpRequest()
    };
    Assert.That(service.GetSession().UserName, Is.EqualTo("Mocked"));

    appHost.Dispose();
}

【讨论】:

  • 感谢您的回复!我非常专注于思考我必须使用我没有考虑手动填充 ISessionFactory 的 SS 方法之一来创建服务。
  • np :) ServiceStack 几乎与简单干净的类和接口绑定在一起,所以大多数时候最简单的事情会起作用:)
  • 效果也很好!只对它进行了一点更改以与 StructureMap 一起使用。
  • @mythz 我在我的一个测试中遇到了空引用异常(你在第 14 行的评论提到了它)......有没有办法从 在服务内?
  • 我在寻找模拟会话时发现了这一点,并且看到您将寻求简化所需的工作。你有没有看过这个?如果是这样,是否有新的策略?谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-18
  • 2010-10-19
  • 2016-09-30
  • 2019-10-06
  • 1970-01-01
  • 2020-10-27
相关资源
最近更新 更多