【问题标题】:Need Help understanding this code需要帮助理解此代码
【发布时间】:2010-11-04 20:26:23
【问题描述】:

我正在尝试学习单元测试。我正在尝试对我在 asp.net mvc 1.0 中制作的一些 Memembership 内容进行单元测试。我一直在关注一本关于 MVC 的书,我对一些希望有人可以为我澄清的东西感到困惑。

我在我的框架中使用 Nunit 和 Moq。

问题一:

  public AuthenticationController(IFormsAuthentication formsAuth, MembershipProvider provider)
        {
            FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
            Provider = provider ?? Membership.Provider;
        }

我有点困惑什么“??”我以前从未真正见过它。就像我什至不知道这里到底发生了什么。就像他们传递界面然后“??”标记发生并制作了一个新的 FormsAuthenticationWraper?

问题 2。

 public AuthenticationController(): this(null, null)
        {
        }

我知道这是默认构造函数,但我不确定为什么 ":this(null,null)" 这样做。

比如它实现了什么?这也指的是什么。最重要的是,为什么不能把它排除在外?并保持默认构造函数不变。

问题 3。

在这本书(asp.net mvc 1.0 快速)中,它谈到了如何实现 Memembership 提供程序需要大量工作。所以他们使用 moq 模型框架来让生活更轻松。

现在我的问题是他们不使用“FormsAuthentication”上的起订量。他们反而制作了一个界面

   public interface IFormsAuthentication
        {
            void SetAuthCookie(string userName, bool createPersistentCookie);
            void SignOut();


        }

然后做一个包装器

公共类 FormsAuthenticationWrapper : IFormsAuthentication { 公共无效 SetAuthCookie(字符串用户名,布尔 createPersistentCookie) { FormsAuthentication.SetAuthCookie(userName, createPersistentCookie); } 公共无效SignOut() { FormsAuthentication.SignOut(); }

}

最后是一个属性

   public IFormsAuthentication FormsAuth
        {
            get;
            private set;
        }

与他们只有会员资格一样

公共静态 MembershipProvider 提供者 { 得到; 私人套装; }

我也不确定要更改哪些内容。就像我也会改变这条线?

FormsAuth = formsAuth ??新的 FormsAuthenticationWrapper();

我还尝试将另一种方法添加到 FormsAuthentication 接口和包装器中。

public void RedirectFromLoginPage(string userName, bool createPersistentCookie) { FormsAuthentication.RedirectFromLoginPage(userName, createPersistentCookie); }

但我不确定发生了什么,但我的单元测试总是失败,这与我尝试修复它无关。

     public ActionResult Login(string returnUrl, FormCollection form, bool rememberMe)
            {
                LoginValidation loginValidation = new LoginValidation();
                try
                {
                    UpdateModel(loginValidation, form.ToValueProvider());

                }
                catch
                {

                    return View("Login");
                }

                if (ModelState.IsValid == true)
                {

                    bool valid = authenticate.VerifyUser(loginValidation.UserName, loginValidation.Password);

                    if (valid == false)
                    {
                        ModelState.AddModelError("frm_Login", "Either the Password or UserName is invalid");

                    }
                    else if (string.IsNullOrEmpty(returnUrl) == false)
                    {
                        /* if the user has been sent away from a page that requires them to login and they do 
                         * login then redirect them back to this area*/
                        return Redirect(returnUrl);
                    }
                    else
                    {

                       FormsAuth.RedirectFromLoginPage(loginValidation.UserName, rememberMe);
                    }

                }


                return View("Login");


Here is my test

[测试] 公共无效 Test_If_User_Is_Redirected_Back_To_Page_They_Came_From_After_Login() { System.Diagnostics.Debugger.Break();

       var formsAuthenticationMock =  new Mock<AuthenticationController.IFormsAuthentication>();

       var membershipMock = new Mock<MembershipProvider>();

       membershipMock.Setup(m => m.ValidateUser("chobo2", "1234567")).Returns(true);


       // Setup controller
       AuthenticationController target = new AuthenticationController(formsAuthenticationMock.Object, membershipMock.Object);


       // Execute
       FormCollection form = new FormCollection();
       form.Add("Username", "chobo2");
       form.Add("password", "1234567");

       ViewResult actual = target.Login(null, form, false) as ViewResult;

       Assert.That(actual.View, Is.EqualTo("home"));
       formsAuthenticationMock.Verify();

   }

Actual 总是返回 null。我尝试了 ViewResult、RedirectResult 和 RedirectToRouteResult,但每个人都返回 null。所以我不确定为什么会发生这种情况,因为我首先觉得很奇怪

                       FormsAuth.RedirectFromLoginPage(loginValidation.UserName, rememberMe);

不停止视图并开始重定向。起初我以为一旦它到达这一行,它就像一个 return 语句,那就是它不会执行其他代码,但 htis 似乎不是这种情况,所以我不确定这是否是问题。

谢谢

【问题讨论】:

  • 你应该把你的问题分成不同的帖子。问题 1 和 2 是相关的,可以是一篇文章,但问题 3 很可能是独立的。
  • 问题3真的不止一个问题

标签: asp.net-mvc unit-testing nunit moq


【解决方案1】:

问题 1

?? 被称为null-coalescing operator,是 C# 2.0 及以后的一个非常有用的功能。

在你的情况下,

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

仅表示“将formsAuth 分配给FormsAuth,除非它为空,在这种情况下分配new FormsAuthenticationWrapper()”。它基本上是一种防止代码中出现空引用的方法。您也可以将其视为以下条件表达式的快捷方式:

FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();

问题 2

this(null, null) 的使用称为constructor chaining。这意味着同一个类中的构造函数(因此this,而不是父类的base)接受两个参数,应该在构造函数的主体执行之前调用。

重载构造函数是一种常见做法,可以让开发人员在只想使用默认属性/设置时更轻松地创建新对象。

问题 3

正如其他人所提到的,这确实属于一个单独的问题。与前两个不同,它更具体地针对上下文/您的代码,而不是 C# 的语言特性。

更新

好的,我现在所做的实际上是重写了这里的两个构造函数,因为我认为将它们放在另一种(实际上等效的)形式可能会更清晰一些,并且可能也是更好的设计实践。这里不需要空值合并运算符。

public AuthenticationController()
    : this(new FormsAuthenticationWrapper(), Membership.Provider)
{
}

public AuthenticationController(IFormsAuthentication formsAuth,
    MembershipProvider provider)
{
    this.FormsAuth = formsAuth;
    this.Provider = provider;
}

在这种形式中,很明显,带有两个参数的构造函数只是将类变量分配给参数的值。无参数构造函数(通常称为 default 构造函数)只需使用 default FormsAuthProvider 对象创建一个新对象,这些对象是通过 构造函数链接指定的.

【讨论】:

  • 嗯,好吧,它开始变得更有意义了。使用默认构造函数,它从控制器继承东西对吗?(我不确定到底继承了什么)。我不知道我是否可以在一百万年后做这些事情,哈哈。我仍然想知道formsAuth什么时候会为空?我没有看到。我还将针对问题 3 发布一个新问题
【解决方案2】:

问题一:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
Provider = provider ?? Membership.Provider;

等于:

FormsAuth = (formsAuth == null ? new FormsAuthenticationWrapper() : formsAuth);
Provider = (provider == null ? Membership.Provider : provider);

问题 2:

它只是将 null 传递给 formsAuth 和提供者构造函数参数。恕我直言,这不是一个好习惯。另一个不带参数的构造函数会更合适。

编辑:这毫无意义。对不起,我很着急,并没有真正意识到这是一个构造函数调用另一个构造函数。

我现在没有时间回答问题 3,我稍后再回答...

【讨论】:

  • 您对问题 2 的回答略有偏差 - 这与添加另一个构造函数不同相同。当您链接构造函数时,就像在 OP 的示例中一样,实际上会执行 both 构造函数。在这种情况下,其中一个恰好是空的......
【解决方案3】:

??操作员说“使用这个,除非它是空的,在这种情况下使用这个其他的东西”。

所以,这行代码:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

等同于:

if ( formsAuth != null ) FormsAuth = formsAuth
else FormsAuth = new FormsAuthenticationWrapper();

【讨论】:

  • 但是如果存在的话,“this()”不是派生类构造函数而不是基类构造函数吗? “base()”在哪里是基类构造函数?
  • “调用基类构造函数”NO! this() 确实 NOT 调用基类构造函数! base() 就是这样做的。请编辑并修复。
  • @kervin & dss539 - 哎呀,完全误读了这个问题。删除了有关调用基类构造函数的误导性内容。
【解决方案4】:

问题 2

public AuthenticationController(): this(null, null)
{
}

AuthenticationController 的无参数构造函数将调用接受 IFormsAuthentication 和 MembershipProvider 的构造函数,传递两个空值(这是在执行无参数构造函数代码块中的任何代码之前完成的)。 由于两个参数的构造函数使用 null-coalescing (??) 运算符来分配变量并且传递的参数为 null,因此使用了新的 MembershipProvider 以及 Membership.Provider 对象。

如果没有显式定义此构造函数,则将使用默认的无参数构造函数。如果创建了新的 AuthenticationController(没有向构造函数传递任何参数),这可能会导致意外行为,因为成员变量不会被初始化。

【讨论】:

    【解决方案5】:

    问题 1: ?? 运算符简单地说“如果它不为空,则取我左边的任何东西 - 如果是,取我右边的任何东西”。所以你的代码:

    FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
    

    等价于

    if (formsAuth != null) {
        FormsAuth = formsAuth;
    } else {
        FormsAuth 0 new FormsAuthenticationWrapper();
    }
    

    问题 2::this(null, null) 语法是“构造函数继承”的简写(我的命名...)。你的代码

    public AuthenticationController(): this(null, null)
        {
        }
    public AuthenticationController(IFormsAuthentication formsAuth, MembershipProvider  provider)
        {
            FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
            Provider = provider ?? Membership.Provider;
        }
    

    等价于

    public AuthenticationController()
        {
            FormsAuth = new FormsAuthenticationWrapper();
            Provider = Membership.Provider;
        }
    public AuthenticationController(IFormsAuthentication formsAuth, MembershipProvider provider)
        {
            FormsAuth = formsAuth;
            Provider = provider;
        }
    

    【讨论】:

    • ic 嗯,我有点喜欢你的方式更好,它更有意义,并且做同样的事情对吗?
    • 正如您在 Noldorin 的回答中看到的那样,问题 2 的示例仅在此特定示例中等效,但并非必需。
    【解决方案6】:

    回答 Q2

    它正在重载构造函数。

    If 表示调用

    Foo() 
    

    和调用一样

    Foo(null, null)
    

    【讨论】:

      【解决方案7】:

      问题 1:??是null coalescing operator。这 ??运算符检查表达式左侧提供的值是否为空,如果是,则返回表达式右侧指示的替代值。

      在您的情况下,它会检查 formsAuth 是否为空,如果为空,则返回一个新的 FormsAuthenticationWrapper()。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-29
        • 1970-01-01
        • 1970-01-01
        • 2015-08-26
        • 1970-01-01
        相关资源
        最近更新 更多