3

このクラスのメソッドを呼び出すMVC3コントローラーをテストしています。

public class SessionVar
{
    /// <summary>
    /// Gets the session.
    /// </summary>
    private static HttpSessionState Session
    {
        get
        {
            if (HttpContext.Current == null)
                throw new ApplicationException
                                   ("No Http Context, No Session to Get!");

            return HttpContext.Current.Session;
        }
    }

    public static T Get<T>(string key)
    {
        return Session[key] == null ? default(T) : (T)Session[key];
    }
    ...
}

ハンゼルマンのブログからの推奨事項に従った私のテスト方法は次のとおりです。

[Test]
public void CanRenderEmployeeList()
{
    _mockIEmployeeService.Setup(s => s.GetEmployees(StatusFilter.OnlyActive))
        .Returns(BuildsEmployeeList().Where(e => e.IsApproved));

    var httpContext = FakeHttpContext();
    var target = _employeeController;
    target.ControllerContext = new ControllerContext
                  (new RequestContext(httpContext, new RouteData()), target);
    var result = target.Index();

    Assert.IsNotNull(result);
    Assert.IsInstanceOf<ViewResult>(result);
    var viewModel = target.ViewData.Model;
    Assert.IsInstanceOf<EmployeeListViewModel>(viewModel);
}

public static HttpContextBase FakeHttpContext()
{
    var context = new Mock<HttpContextBase>();
    var request = new Mock<HttpRequestBase>();
    var response = new Mock<HttpResponseBase>();
    var session = new Mock<HttpSessionStateBase>();
    var server = new Mock<HttpServerUtilityBase>();

    context.Setup(ctx => ctx.Request).Returns(request.Object);
    context.Setup(ctx => ctx.Response).Returns(response.Object);
    context.Setup(ctx => ctx.Session).Returns(session.Object);
    context.Setup(ctx => ctx.Server).Returns(server.Object);

    return context.Object;
}

しかし、私のテストは失敗し続けます、私は得ます:

CanRenderEmployeeListSystem.ApplicationException : No Http Context, 
                                                          No Session to Get!

これは、次の場合にスローされる例外メッセージです。HttpContext.Current == null

セッションに保存されている実際の値ではなく、Sessionオブジェクトが「存在する」必要があります。

私が間違っていることを教えてもらえますか?

ありがとう。

4

2 に答える 2

2

長期的には、SessionVarクラスのインターフェイスを作成するとさらに幸せになります。実行時に(依存性注入を介して)現在の実装を使用します。テスト中にモックを接続します。これらのHttpランタイム依存関係をすべてモックアウトする必要がなくなります。

于 2012-10-12T22:59:40.487 に答える
2

SessionプロパティのHttpContext.Currentは、作成しているモックされたHttpContextBaseの影響を受けません。つまり、ローカルのHttpContextBaseを作成するだけでは、HttpContext.Currentに自動的にデータが入力されません。実際、HttpContextとHttpContextBaseは実際には関連していません。それらを統合するには、HttpContextWrapperを使用する必要があります。

したがって、HttpContextWrapper実装をクラスSessionVarに渡す方がよいでしょう。以下のコードでは、コンストラクターでコンテキストを設定できるように、メソッドとプロパティをインスタンスレベルに変更しました。コンストラクターにコンテキストが渡されない場合は、HttpContext.Currentと見なされますが、モックされたインスタンスをテストに渡すこともできます。

public class SessionVar
{
    HttpContextWrapper m_httpContext;

    public SessionVar(HttpContextWrapper httpContext = null)
    {
        m_httpContext = httpContext ?? new HttpContextWrapper(HttpContext.Current);
    }

    /// <summary>
    /// Gets the session.
    /// </summary>
    private HttpSessionState Session
    {
        get
        {
            if (m_httpContext == null)
                throw new ApplicationException("No Http Context, No Session to Get!");

            return m_httpContext.Session;
        }
    }

    public T Get<T>(string key)
    {
        return Session[key] == null ? default(T) : (T)Session[key];
    }
    ...
}
于 2012-10-13T00:30:01.030 に答える