单元测试它调用会话对象的动作, [英] Unit-testing an action which calls session object

查看:174
本文介绍了单元测试它调用会话对象的动作,的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我怎么能单元测试,它使用一个会话对象的身体内部的方法是什么?

让我们说我有以下作用:

  [HttpPost]
公共JsonResult GetSearchResultGrid(JqGridParams gridParams中GUID campaignId,串queryItemsString)
{
    VAR queryItems =新JavaScriptSerializer()反序列化<。IList的< FilledQueryItem>>(queryItemsString);
    IPageData pageData = gridParams.ToPageData();
    VAR extraFieldLinker = SessionHandler.CurrentExtraFieldsLinker;
    VAR searchParams =新SearchParamsModel(extraFieldLinker,queryItems);
    IList的< CustomerSearchResultRow>的SearchResult = NULL;
    的SearchResult = _customerService.SearchCustomersByUrlAndCampaign(campaignId,
        sea​​rchParams.SearchString,
        sea​​rchParams.AddressFilter predicate,
        pageData);
    返回GetGridData< CustomerSearchResultGridDefinition,CustomerSearchResultRow>(SearchResult所,pageData);
}
 

我做了以下的单元测试其失败的,到目前为止,因为会话的事情:

  [测试]
公共无效CanGetSearchResultGrid()
{
    //初始化
    VAR mockJqGridParams =新的模拟< JqGridParams>();
    VAR mockPageData =新的模拟< IPageData>();
    IPagedList< CustomerSearchResultRow> mockPagedResult =新PagedList< CustomerSearchResultRow>(mockPageData.Object);
    变种GUID = Guid.NewGuid();
    常量字符串searchString =
        "[{\"Caption\":\"FirstName\",\"ConditionType\":\"contains\",\"Value\":\"d\",\"NextItem\":\"Last\"}]";
    FUNC<地址,布尔> addressFilter predicate =(X =>真正的);

    //建立
    mockJqGridParams.Setup(X => x.ToPageData())返回(mockPageData.Object);
    _customerService.Setup(X => x.SearchCustomersByUrlAndCampaign(GUID,searchString,addressFilter predicate,mockPageData.Object))
        .Returns(mockPagedResult);

    //呼叫
    VAR的结果= _homeController.GetSearchResultGrid(mockJqGridParams.Object,GUID,searchString);

    mockJqGridParams.Verify(X => x.ToPageData(),Times.Once());
    _customerService.Verify(X => x.SearchCustomersByUrlAndCampaign(GUID,searchString,addressFilter predicate,mockPageData.Object)
        ,Times.Once());

    //校验
    Assert.That(结果,Is.Not.Null);
    Assert.That(结果,Is.TypeOf(typeof运算(JsonResult)));
}
 

和从课程的辅助方法:

 公共静态ExtraFieldsLinker CurrentExtraFieldsLinker
    {
        得到
        {
            反对extraFieldLinker = GetSessionObject(EXTRA_FIELDS_LINKER);
            返回extraFieldLinker为ExtraFieldsLinker;
        }
        集合{SetSessionObject(EXTRA_FIELDS_LINKER,价值); }
    }
 

解决方案

我已经解决了类似的问题(使用静态数据访问未嘲弄友好的 - 尤其是, HttpContext.Current )通过包装在另一对象的访问,并通过接口访问它。你可以这样做:

 耻骨接口ISessionData
{
    ExtraFieldsLinker CurrentExtraFieldsLinker {获得;组; }
}

公共类SessionDataImpl:ISessionData
{
    ExtraFieldsLinker CurrentExtraFieldsLinker
    {
        //注:此code是有点假,
        //因为我认为这些都是你的类的方法。
        //但它说明了这一点。你把所有的访问这里
        {返回(ExtraFieldsLinker)GetSessionObject(EXTRA_FIELDS_LINKER); }
        集合{SetSessionObject(EXTRA_FIELDS_LINKER,价值); }
    }
}

公共类ClassThatContainsYourAction
{
    静态ClassThatContainsYourAction()
    {
        SessionData =新SessionDataImpl();
    }

    公共静态ISessionData SessionData {获得;私定; }

    //使这种访问非常难看,这样你就不是偶然做
    公共无效SetSessionDataForUnitTests(ISessionData sessionData)
    {
        SessionData = sessionData;
    }

    [HttpPost]
    公共JsonResult GetSearchResultGrid(JqGridParams gridParams,
        GUID campaignId,串queryItemsString)
    {
        VAR queryItems = // ...
        IPageData pageData = // ...

        //你的访问只能通过SessionData共享状态
        VAR extraFieldLinker = SessionData.CurrentExtraFieldsLinker;

        // ...
    }
}
 

那么你的单元测试可以在调用 GetSearchResultGrid 设置 ISessionData 实例模拟对象。

在理想情况下,你会使用一个依赖注入库在某些时候,和摆脱静态构造函数。

如果您能想出一个办法让你的 ISessionData 实例化对象,而不是静态的,甚至更好。对象模拟框架往往喜欢创建新的模拟类型,每一个测试用例,并有嘲笑从previous测试周围地势是种毛。我相信,会话状态将是全局会话无论如何,所以你可能没有做任何事情棘手,使非静态对象的工作。

How can I unit test a method which uses a session object inside of its body?

Let us say I have the following action:

[HttpPost]
public JsonResult GetSearchResultGrid(JqGridParams gridParams, Guid campaignId, string queryItemsString)
{
    var queryItems = new JavaScriptSerializer().Deserialize<IList<FilledQueryItem>>(queryItemsString);
    IPageData pageData = gridParams.ToPageData();
    var extraFieldLinker = SessionHandler.CurrentExtraFieldsLinker;
    var searchParams = new SearchParamsModel(extraFieldLinker, queryItems);
    IList<CustomerSearchResultRow> searchResults = null;
    searchResults = _customerService.SearchCustomersByUrlAndCampaign(campaignId,
        searchParams.SearchString,
        searchParams.AddressFilterPredicate,
        pageData);
    return GetGridData<CustomerSearchResultGridDefinition, CustomerSearchResultRow>(searchResults, pageData);
}

I made the following unit tests which fails so far because of the session thing:

[Test]
public void CanGetSearchResultGrid()
{
    //Initialize
    var mockJqGridParams = new Mock<JqGridParams>();
    var mockPageData = new Mock<IPageData>();
    IPagedList<CustomerSearchResultRow> mockPagedResult = new PagedList<CustomerSearchResultRow>(mockPageData.Object);
    var guid= Guid.NewGuid();
    const string searchString =
        "[{\"Caption\":\"FirstName\",\"ConditionType\":\"contains\",\"Value\":\"d\",\"NextItem\":\"Last\"}]";
    Func<Address,bool> addressFilterPredicate = (x => true);

    //Setup
    mockJqGridParams.Setup(x => x.ToPageData()).Returns(mockPageData.Object);
    _customerService.Setup(x => x.SearchCustomersByUrlAndCampaign(guid, searchString, addressFilterPredicate, mockPageData.Object))
        .Returns(mockPagedResult);

    //Call
    var result = _homeController.GetSearchResultGrid(mockJqGridParams.Object, guid, searchString);

    mockJqGridParams.Verify(x => x.ToPageData(), Times.Once());
    _customerService.Verify(x => x.SearchCustomersByUrlAndCampaign(guid, searchString, addressFilterPredicate, mockPageData.Object)
        , Times.Once());

    //Verify
    Assert.That(result, Is.Not.Null);
    Assert.That(result, Is.TypeOf(typeof(JsonResult)));
}

And the method from the helper of course:

   public static ExtraFieldsLinker CurrentExtraFieldsLinker
    {
        get
        {
            object extraFieldLinker = GetSessionObject(EXTRA_FIELDS_LINKER);
            return extraFieldLinker as ExtraFieldsLinker;
        }
        set { SetSessionObject(EXTRA_FIELDS_LINKER, value); }
    }

解决方案

I've solved similar issues (use of static data accessors that aren't mock friendly - in particular, HttpContext.Current) by wrapping the access in another object, and accessing it through an interface. You could do something like:

pubic interface ISessionData
{
    ExtraFieldsLinker CurrentExtraFieldsLinker { get; set; }
}

public class SessionDataImpl : ISessionData
{
    ExtraFieldsLinker CurrentExtraFieldsLinker
    {
        // Note: this code is somewhat bogus,
        // since I think these are methods of your class.
        // But it illustrates the point.  You'd put all the access here
        get { return (ExtraFieldsLinker)GetSessionObject(EXTRA_FIELDS_LINKER); }
        set { SetSessionObject(EXTRA_FIELDS_LINKER, value); }
    }
}

public class ClassThatContainsYourAction
{
    static ClassThatContainsYourAction()
    {
        SessionData = new SessionDataImpl();
    }

    public static ISessionData SessionData { get; private set; }

    // Making this access very ugly so you don't do it by accident
    public void SetSessionDataForUnitTests(ISessionData sessionData)
    {
        SessionData = sessionData;
    }

    [HttpPost]
    public JsonResult GetSearchResultGrid(JqGridParams gridParams,
        Guid campaignId, string queryItemsString)
    {
        var queryItems = // ...
        IPageData pageData = // ...

        // Access your shared state only through SessionData
        var extraFieldLinker = SessionData.CurrentExtraFieldsLinker;

        // ...
    }
}

Then your unit test can set the ISessionData instance to a mock object before calling GetSearchResultGrid.

Ideally you'd use a Dependency Injection library at some point, and get rid of the static constructor.

If you can figure out a way to make your ISessionData an instanced object instead of static, even better. Mock object frameworks tend to like to create a new mock type for every test case, and having mocks lying around from previous tests is kind of gross. I believe session state is going to be global to your session anyway, so you might not have to do anything tricky to make a non-static object work.

这篇关于单元测试它调用会话对象的动作,的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆