我正在尝试学习单元测试。我正在尝试对我在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似乎不是这样的,所以我不确定这是否可能是问题。
由于
答案 0 :(得分:11)
??
被称为null-coalescing operator,是C#2.0以后非常有用的功能。
在你的情况下,
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
只是表示“将formsAuth
分配给FormsAuth
,除非它为空,在这种情况下指定new FormsAuthenticationWrapper()
”。它基本上是一种阻止代码中空引用的方法。您还可以将其视为以下条件表达式的快捷方式:
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
使用this(null, null)
称为constructor chaining。所有这些意味着,在执行构造函数的主体之前,应该调用同一类中的构造函数(因此this
,而不是父类的base
),它接受两个参数。
重载构造函数是一种常见的做法,可以让开发人员在只想使用默认属性/设置时更容易创建新对象。
正如其他人所提到的,这确实属于一个单独的问题。与前两个不同,它更具体地针对上下文/您的代码,而不是C#的语言特性。
好的,我现在所做的实际上是在这里改写了两个构造函数,因为我认为将它们放在另一个(几乎等效的)形式中可能会更清晰一点,并且可能也是更好的设计实践。这里不需要空合并运算符。
public AuthenticationController()
: this(new FormsAuthenticationWrapper(), Membership.Provider)
{
}
public AuthenticationController(IFormsAuthentication formsAuth,
MembershipProvider provider)
{
this.FormsAuth = formsAuth;
this.Provider = provider;
}
在这种形式中,显而易见的是,带有两个参数的构造函数只是将类变量赋给参数的值。无参数构造函数(通常称为默认构造函数)只是使用默认 FormsAuth
和Provider
对象创建一个新对象,这些对象通过< 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(没有将任何参数传递给构造函数),这可能会导致意外行为,因为成员变量不会被初始化。