2009-06-22 3 views
2

Я пытаюсь изучить модульное тестирование. Я пытаюсь выполнить тестирование некоторых элементов Memembership, которые я делаю в asp.net mvc 1.0. Я следил за книгой о 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) 
     { 
     } 

Я знаю, что это конструктор по умолчанию, но я не знаю, почему ": это (NULL, NULL)" делает.

Как он реализуется? и что это касается тоже. И, кроме того, почему это не может быть просто опущено? И просто придерживайтесь конструктора по умолчанию, как есть.

Вопрос 3.

В книге (asp.net MVC 1.0 быстро), что говорит о том, как это было бы совсем немного работы по реализации поставщика Memembership будет много работы. Поэтому они используют фреймворк moq для облегчения жизни.

Теперь, мой вопрос в том, что они не используют moq в «FormsAuthentication». Вместо этого они делают интерфейс

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


     } 

Затем сделать обертку

класса FormsAuthenticationWrapper общественности: IFormsAuthentication { общественного недействительным SetAuthCookie (строка имя_пользователь, BOOL createPersistentCookie) { FormsAuthentication.SetAuthCookie (Username, createPersistentCookie); } public void SignOut() { FormsAuthentication.SignOut(); }

} 

Тогда, наконец, свойство

public IFormsAuthentication FormsAuth 
     { 
      get; 
      private set; 
     } 

Где, как с членством они только

общественный статический MembershipProvider Provider { ПОЛУЧИТЬ; частный набор; }

Я не уверен, что что менять тоже. Как я тоже изменил бы эту линию?

FormsAuth = formsAuth ?? новый FormsAuthenticationWrapper();

Я также попытался добавить еще один метод в интерфейс FormsAuthentication и Wrapper.

общественного недействительный RedirectFromLoginPage (строка имя_пользователь, 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(); 

    } 

Фактический всегда возвращается к нулю. Я пробовал ViewResult, RedirectResult и RedirectToRouteResult, но все возвращаются в нуль. Поэтому я не знаю, почему это происходит, так как я нахожу это странным, что первый

     FormsAuth.RedirectFromLoginPage(loginValidation.UserName, rememberMe); 

не останавливает взгляд и начинает перенаправлять. Я подумал, что сначала, когда он попадает в эту строку, это похоже на оператор return, и это не значит, что другой код не будет выполнен, но, похоже, это не так, поэтому я не уверен, что это может быть проблемой.

Thanks

+1

Вы должны, вероятно, разделить свои вопросы в отдельных сообщениях. Вопросы 1 и 2 связаны друг с другом, и это может быть одна должность, но вопрос 3, скорее всего, будет сам по себе. –

+0

Вопрос 3 - это более чем один вопрос действительно –

ответ

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#.

Update

Хорошо, что я сделал сейчас на самом деле переписать два конструктора здесь, так как я думаю, поместив их в другой (практически эквивалентной) форме может быть немного яснее, и, вероятно, лучше дизайн практика слишком , Нулевой оператор коалесцирования здесь не нужен.

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

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

В этой форме, должно быть очевидно, что конструктор, который принимает два параметра просто присваивает переменным класса к значениям аргументов. Конструктор без параметров (часто называемого конструктора по умолчанию) просто создает новый объект, используя по умолчаниюFormsAuth и Provider объектов, которые определены с помощью конструктора цепочки.

+0

Хм, хорошо, это начинает иметь больше смысла. С конструктором по умолчанию он наследует материал от контроллера? (Я не уверен, что именно наследуется, хотя). Я не знаю, мог ли я когда-либо делать это за миллион лет. Мне все еще интересно, когда будет так, что formsAuth будет null? Я этого не вижу. Я также опубликую новый вопрос на вопрос 3 – chobo2

+0

@ chobo2: Смотрите мое обновленное сообщение. – Noldorin

1

Вопрос 1: ?? это null coalescing operator. The ?? оператор проверяет, является ли значение, представленное в левой части выражения, нулевым, и если это так, то возвращается альтернативное значение, указанное правой частью выражения.

В вашей ситуации он проверяет, является ли formsAuth нулевым и возвращает новый FormsAuthenticationWrapper(), если он равен NULL.

1

The ?? оператор говорит: «Используйте это, если это не пустое, в каком случае эта другая вещь».

Таким образом, эта строка кода:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 

То же самое, как:

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

Но не будет ли это «()« конструктором производного класса, если он существует, а не конструктор базового класса? Где в качестве "base()" быть конструктором базового класса? – kervin

+0

"вызов конструктора базового класса" NO! this() делает ** NOT ** вызывает конструктор базового класса! base() делает это. Пожалуйста отредактируйте и исправьте. – dss539

+0

@kervin & dss539 - Ой, совершенно неправильно прочитал вопрос. Удалил вводящий в заблуждение материал о вызове конструктора базового класса. –

0

В ответ на Q2

Это перегружает конструктор.

Если означает, что вызов

Foo() 

такая же, как вызов

Foo(null, null) 
0

Вопрос 1:

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

это равняется:

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

Вопрос 2:

Это просто передается значение null в обеих аргументах аргумента atom и поставщика. Это не хорошая практика ИМХО. Другой конструктор без аргументов будет лучше подходит.

EDIT: Это не имеет никакого смысла. Извините, я торопился и не понимал, что это конструктор, вызывающий другого конструктора.

У меня нет времени, чтобы ответить на вопрос 3 прямо сейчас, я вернусь к этому позже ...

+0

Ваш ответ на вопрос 2 слегка выключен - это не * только * то же, что и добавление другого конструктора. Когда вы связываете конструкторы, как в примерах OP, * оба * конструктора фактически выполняются. В этом случае один из них просто оказывается пустым ... –

+0

«Это не хорошая практика», потому что ...? – dss539

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; 
    } 
+0

ic hmm Я вроде как ваш путь лучше, он имеет больше смысла с места в карьер и делает то же самое правильно? – chobo2

+0

Как вы можете видеть в ответе Нолдорина, примеры для вопроса 2 эквивалентны только в этом конкретном примере, но не по необходимости. –

0

Вопрос 2

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

нет конструктора параметр AuthenticationController будет вызывать конструктор, который принимает IFormsAuthentication и MembershipProvider, проходя два нулевые значения (это делается до того, как выполняется выполнение любого кода в блоке кода конструктора no-param). Поскольку два конструктора аргументов используют оператор с нулевым коалесцированием (??) для назначения переменных, а переданные аргументы равны нулю, новый членский пакет используется вместе с объектом Membership.Provider.

Если бы этот конструктор не был определен явно, конструктор no-param по умолчанию был бы использован. Это может привести к неожиданному поведению, если был создан новый AuthenticationController (без передачи каких-либо аргументов конструктору), поскольку переменные-члены не были бы инициализированы.

Смежные вопросы