【问题标题】:How to mock a method that returns an int with MOQ如何使用 MOQ 模拟返回 int 的方法
【发布时间】:2010-10-18 19:31:34
【问题描述】:

我有一个类可以检索一些内容,并且它有一个在检索之前需要一些输入(过滤器)的方法。其中一个“输入”调用另一个方法,该方法基本上返回一个 int,我如何使用 MOQ 模拟它?这是一个例子:

namespace MyNamespace
{
    public class ConfigMetaDataColumns : MyModel
    {
        public int FieldID { get { return ValueInt("FieldID"); } }
        public int OrderId { get { return ValueInt("OrderId"); } }
        public string Label { get { return ValueString("Label"); } }
        public string FieldName { get { return ValueString("FieldName"); } }
        public int IsReadOnly { get { return ValueInt("IsReadOnly"); } }
    }

    public class GetDataClass
    {
        protected OpenSQLAccessLayer m_WITObject;

        // Input Properties
        public string GroupID;
        public string PageName;

        // Output Properties

        /// <summary>
        /// Get Config meta data
        /// </summary>
        /// <returns></returns>
        public IEnumerable<ConfigMetaDataColumns> GetConfigMetaData()
        {
            var requester = new ListRequester<OpenSQL, ConfigMetaDataColumns>(m_WITObject, "Result[0].RowCount", "Result[0].Row[{0}].");

            return requester.Items;
        }

        public void InitRequest()
        {
            User user = (User)HttpContext.Current.User;
            m_WITObject = user.NewService<OpenSQLAccessLayer>();

            m_WITObject.SetInput("MultipleResultSets", 1);
            m_WITObject.SetInput("ClientID", Utils.GetClientID());
            m_WITObject.SetInput("GroupID", GroupID);
            m_WITObject.SetInput("PageName", PageName);
            m_WITObject.Retrieve();
        }
    }
}

这是“GetClientID()”方法:

public static int GetClientID()
        {
            User oUser = (User)HttpContext.Current.User;
            int nClientID;
            string sClientID = string.Empty;

            if (String.IsNullOrEmpty(oUser.Session("clientid")))
            {
                Client oClient = new Client();
            }

            oUser = (User)HttpContext.Current.User;
            sClientID = oUser.Session("clientid");




            //If we couldn't retrieve it, throw exception
            if ( string.IsNullOrEmpty(sClientID) || !int.TryParse(sClientID, out nClientID))
            {
                throw new Exception("No clientid found in user session, client not authenticated, please login from main page");
            }

            return nClientID;
        }

我只是在寻找一种方法来传递 ClientID 的硬编码值,并使用它对 GetDataClass 类进行一些单元测试。

谢谢。

【问题讨论】:

  • 不回答你的问题,因为克劳斯比斯科夫已经做得很好了。但我想说的是,我喜欢使用 AppContext 类而不是“Util”类(它实现了 IAppContext,与 klausbyskov 的回答中的 IUtil 相同)。它存储有关应用程序当前上下文的信息,例如当前用户、当前客户端或您可能需要在整个应用程序中了解的其他活动配置。当然,这都是个人喜好,但我认为 AppContext 类的意图比另一个名为“Utils”的类更清楚。
  • 感谢您的建议,不幸的是,这些课程来自不同的团队,并且是我无法更改的“核心”库的一部分!我只是继承它。

标签: c# .net moq


【解决方案1】:

您不能模拟静态方法。您应该使用一些依赖注入的方法。假设您将 GetClientId 方法作为名为 IUtils 的接口的一部分,如下所示:

public interface IUtils
{
    int GetClientId();
} 

你的具体类Utils 实现如上,但方法不是静态的(当然也实现了接口)。 您现在将接口的实现注入GetDataClass 通过更改其构造函数来创建类,如下所示:

public class GetDataClass
{
     private readonly IUtils utils;

     public GetDataClass(IUtils utils)
     {
         this.utils = utils;
     }

     //SNIP
}

在InitRequest 方法中,您将调用Utils.GetClientID() 更改为this.utils.GetClientId()。

您现在已准备好使用模拟实例化您的 GetDataClass 类,如下所示:

var utilsMock = new Mock<IUtils>();
utilsMock.Setup(u => u.GetClientId()).Returns(42);

var getDataClass = new GetDataClass(utilsMock.Object);
getDataClass.InitRequest();

就是这样。

【讨论】:

  • 您好 klausbyskov,不幸的是,“Utils”类(以及许多其他类已经由不同的团队实现!),没有一个是接口的实现,所以我无法进行任何更改给它。也许,我应该改写我的问题:根据我原来的问题中的信息,我如何测试 "GetDataClass" (它需要调用 "InitRequest" 来做一些初始化),特别是调用 "GetConfigMetaData()" ?谢谢。
  • 是什么阻止你重构其他团队'的代码?毕竟,你们都在同一条船上。如果您解释了使代码可测试的意图,我相信如果他们不想在专业上看起来像完全傻瓜,他们将必须尝试满足您的愿望。从长远来看,在您的开发中使用行业最佳实践对您所有都有好处,这肯定包括编写可测试的代码。因此,与其寻找不应该存在的设计问题的解决方案(不存在),不如重构代码。应该没什么大不了的。
  • 这个类(在许多其他类中)是一个“核心”库的一部分,该库由一个不同的团队编写,被大约 15 个不同的项目使用。我在这里很新,所以我的声音在管道中很重要:) 但很公平,我会敦促这个库重构可测试代码。谢谢!
  • @Saxman,我知道这对您来说可能是个问题,但这是您注入 Moq 模拟的唯一方法。静态方法根本无法模拟。祝你好运。
猜你喜欢
  • 1970-01-01
  • 2013-03-26
  • 1970-01-01
  • 2010-12-19
  • 2011-04-17
  • 1970-01-01
  • 1970-01-01
  • 2010-10-08
相关资源
最近更新 更多