需要帮助了解此代码

时间:2009-06-22 12:53:05

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

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

我正在使用Nunit和Moq作为我的框架。

问题1:

  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”上的moq。他们改为制作一个界面

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


        }

然后制作一个包装

公共类FormsAuthenticationWrapper:IFormsAuthentication     {         public void SetAuthCookie(string userName,bool createPersistentCookie)         {             FormsAuthentication.SetAuthCookie(userName,createPersistentCookie);         }         public void SignOut()         {             FormsAuthentication.SignOut();         }

}

然后最后一个属性

   public IFormsAuthentication FormsAuth
        {
            get;
            private set;
        }

与成员一样,他们只有

public static MembershipProvider Provider     {         得到;         私人集;     }

我不确定该怎样改变这些东西。就像我改变这一行一样呢?

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

我还尝试在FormsAuthentication接口和Wrapper中添加另一种方法。

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

[测试]        public void 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();

   }

实际总是回到null。我尝试了ViewResult,RedirectResult和RedirectToRouteResult但是每个人都回来了。所以我不确定为什么会这样,因为我发现它很奇怪

                       FormsAuth.RedirectFromLoginPage(loginValidation.UserName, rememberMe);

不会停止视图并开始重定向。我一开始认为一旦它到达这一行它就像一个return语句,并且没有其他代码会被执行但是htis似乎不是这样的,所以我不确定这是否可能是问题。

由于

7 个答案:

答案 0 :(得分:11)

问题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;
}

在这种形式中,显而易见的是,带有两个参数的构造函数只是将类变量赋给参数的值。无参数构造函数(通常称为默认构造函数)只是使用默认 FormsAuthProvider对象创建一个新对象,这些对象通过< em>构造函数链接。

答案 1 :(得分:1)

问题1:??是null coalescing operator。 ?? ?? operator检查表达式左侧提供的值是否为null,如果是,则返回表达式右侧指示的备用值。

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

答案 2 :(得分:1)

??运营商说“使用这个,除非它是空的,它在哪种情况下使用另一个东西”。

所以,这行代码:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

与:

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

答案 3 :(得分:0)

回答Q2

它正在重载构造函数。

如果意味着调用

Foo() 

与调用

相同
Foo(null, null)

答案 4 :(得分:0)

问题1:

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

等于:

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

问题2:

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

编辑:这没有任何意义。对不起,我很匆忙,并没有真正意识到这是一个构造函数调用另一个构造函数。

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

答案 5 :(得分:0)

问题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;
    }

答案 6 :(得分:0)

问题2

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

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

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