Нужна помощь в понимании этого кода - PullRequest
2 голосов
/ 22 июня 2009

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

Я знаю, что это конструктор по умолчанию, но я не уверен, почему ": this (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 { public void SetAuthCookie (строка userName, bool createPersistentCookie) { FormsAuthentication.SetAuthCookie (userName, createPersistentCookie); } public void SignOut () { FormsAuthentication.SignOut (); }

}

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

   public IFormsAuthentication FormsAuth
        {
            get;
            private set;
        }

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

публичный статический поставщик MembershipProvider { получить; приватный набор; }

Я не уверен, хотя, что изменить вещи тоже. Например, что бы я тоже изменил эту строку?

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

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

public void RedirectFromLoginPage (строка 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] 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();

   }

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

                       FormsAuth.RedirectFromLoginPage(loginValidation.UserName, rememberMe);

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

Спасибо

Ответы [ 7 ]

11 голосов
/ 22 июня 2009

Вопрос 1

?? называется нуль-коалесцирующим оператором и является очень полезной функцией C # 2.0 и далее.

В вашем случае

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

просто означает «присвоить formsAuth FormsAuth, если оно не равно нулю, в этом случае назначьте new FormsAuthenticationWrapper()». Это в основном способ предотвращения пустых ссылок в вашем коде. Вы также можете рассматривать его как ярлык для следующего условного выражения:

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

Вопрос 2

Использование this(null, null) называется конструкторская цепочка . Все это означает, что конструктор в том же классе (следовательно, 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 FormsAuth и Provider, которые задаются с помощью конструкторской цепочки .

1 голос
/ 22 июня 2009

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

Итак, эта строка кода:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

Так же, как:

if ( formsAuth != null ) FormsAuth = formsAuth
else FormsAuth = new FormsAuthenticationWrapper();
1 голос
/ 22 июня 2009

Вопрос 1: ?? является оператором объединения нулей . ?? Оператор проверяет, является ли значение, указанное в левой части выражения, нулевым, и если да, то возвращает альтернативное значение, указанное в правой части выражения.

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

0 голосов
/ 22 июня 2009

Вопрос 2

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

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

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

0 голосов
/ 22 июня 2009

Вопрос 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 голосов
/ 22 июня 2009

Вопрос 1:

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

равно:

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

Вопрос 2:

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

РЕДАКТИРОВАТЬ : Это не имеет смысла. Извините, я спешил и не понял, что это конструктор, вызывающий другого конструктора.

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

0 голосов
/ 22 июня 2009

В ответ на Q2

Перегрузка конструктора.

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

Foo() 

- это то же самое, что

Foo(null, null)
...