2013-11-09 3 views
3

Я пытаюсь узнать об модульном тестировании с помощью нового проекта VS2013 MVC w/Authentication Project. Одной из первых вещей, которые я хочу проверить, является регистрация пользователя. (Я знаю, что мне, вероятно, не нужно тестировать это, поскольку это уже проверенный MS код, но я хочу использовать это, чтобы понять основы). Я также слышал, что новый код членства более «проверен», поэтому мне не нужно создавать собственные интерфейсы членства и т. Д.Тестирование модуля MVC Authentication VS 2013

Я использую NSubstitute как фальшивую структуру.

Глядя на контроллер Account -> Register() метод асинхронной

namespace WebApplication1.Controllers 
{ 
    [Authorize] 
    public class AccountController : Controller 
    { 
     public AccountController() 
     : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()))) 
     { 
     } 

     public AccountController(UserManager<ApplicationUser> userManager) 
     { 
      UserManager = userManager; 
     } 

     public UserManager<ApplicationUser> UserManager { get; private set; } 

     ... 


     // 
     // POST: /Account/Register 
     [HttpPost] 
     [AllowAnonymous] 
     [ValidateAntiForgeryToken] 
     public async Task<ActionResult> Register(RegisterViewModel model) 
     { 
      if (ModelState.IsValid) 
      { 
       var user = new ApplicationUser() { UserName = model.UserName }; 
       var result = await UserManager.CreateAsync(user, model.Password); 
       if (result.Succeeded) 
       { 
        await SignInAsync(user, isPersistent: false); 
        return RedirectToAction("Index", "Home"); 
       } 
       else 
       { 
        AddErrors(result); 
       } 
      } 

      // If we got this far, something failed, redisplay form 
      return View(model); 
     } 

Если бы я хотел написать простой тест (напр Register_RegisterValidUser.), Как бы я это сделать? Я знаю, что нужно заменить на UserManager каким-то образом, но это не работает для меня:

var substitute = Substitute.For<UserManager<ApplicationUser>>(); 

Я также понимаю, что мне нужно обойти Task асинхронной <> функции с помощью Task.FromResult, но я не знаю, как для возврата действительных объектов из методов CreateAsync() и SigninAsync().

Может ли кто-нибудь помочь с примером тестового кода? Большое спасибо!

ответ

1

издеваться менеджера пользователя с NSubstitute вы должны использовать это:

var userStore = Substitute.For<IUserStore<ApplicationUser>>(); 
var userManager = Substitute.For<UserManager<ApplicationUser>>(userStore); 

Теперь вы можете подделать методы приводят тоже. Например:

userManager.FindByNameAsync(Arg.Any<string>()).Returns(Task.FromResult(new ApplicationUser())); 

Надеюсь, это поможет вам.

+0

Пила это и пробовала, и она работает ! Спасибо –

1

Тест Руководство

Вы можете проверить блок пару поведения, но я просто покажу вам направление для одного теста единицы, которые просто проверить, является ли получить правильное значение RedirectToAction. Например,

return RedirectToAction («Index», «Home»);

Улучшение Тестируемость

В своем вопросе вы упомянули

Я также слышал, что новый код членства более «проверяемым», поэтому я не нужно создавать мои собственные членские интерфейсы и т. д.

Хотя это правда, я сделал бы небольшую корректировку, чтобы мы n сделать ваш бит реализации более надежным. Таким образом, ваш модульный тест может чисто сконцентрироваться на конкретном поведении вашего теста. Другими словами, мы можем сделать ваш SUT (System Under Test) более надежным.

await SignInAsync(user, isPersistent: false); 

Я считаю, что SignInAsync - это частный метод. В этом методе должно быть какое-то поведение, которое вы, вероятно, можете извлечь из отдельной реализации, которую вы можете ввести в SUT. Мы можем назвать это ISignInManager

public interface ISignInManager { 
    Task SignInAsync(ApplicationUser user, bool isPersistent); 
} 

Преимущество этого в том, что теперь вы можете вводить behaiovr в качестве ISignInManager для выполнения задач и ваш зарегистрировались SUT стать более проверяемым. Вы должны увидеть, что в вашем модульном тесте будет меньше насмешек/стуков и сделайте ваш тест более легким для написания и понимания.

Unit Test

Вы можете воспользоваться преимуществами новых асинхронным/ожидает использование метода MSTest. Это упрощает сложные и ненадежные тесты, которые мы использовали для написания.

Тестирование модуля, которое проверяет правильность маршрута маршрутизации/методы действий, может быть записано, как показано ниже.

[TestMethod] 
    public async Task Register_RegisterValidUser_EnsureRedirectToIndexActionHomeController() 
    { 
     // Arrange 
     var userManagerStub = Substitute.For<IUserManager<ApplicationUser>>(); 
     var tcs = new TaskCompletionSource<IdentityResult>(); 
     tcs.SetResult(new IdentityResult(true)); 
     userManagerStub.CreateAsync(Arg.Any<ApplicationUser>(), Arg.Any<string>()).Returns(tcs.Task); 

     var signInManagerStub = Substitute.For<ISignInManager>>(); 

     signInManagerStub.Setup(s => s.SignInAsync(It.IsAny<ApplicationUser>(), It.IsAny<bool>())).Returns(Task.FromResult(true)); 

     var sut = new AccountController(userManagerStub) { SignInManager = signInManagerStub.Object }; 

     // Act 
     var result = await sut.Register(new RegisterViewModel() { Password = "fakePw" }) as RedirectToRouteResult; 

     // Assert 
     Assert.AreEqual<string>("Index", result.RouteValues["action"].ToString()); 
     Assert.AreEqual<string>("Home", result.RouteValues["controller"].ToString()); 
    } 

выше использует NSubstitute в качестве основы изоляции, но если кто-то заинтересован в версии MOq, пожалуйста, смотрите ниже.

[TestMethod] 
    public async Task Register_RegisterValidUser_EnsureRedirectToIndexHome() 
    { 
     // Arrange 
     var userManagerStub = new Mock<IUserManager<ApplicationUser>>(); 
     var tcs = new TaskCompletionSource<IdentityResult>(); 
     tcs.SetResult(new IdentityResult(true)); 
     userManagerStub.Setup(s => s.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>())).Returns(tcs.Task); 

     var signInManagerStub = new Mock<ISignInManager>(); 
     signInManagerStub.Setup(s => s.SignInAsync(It.IsAny<ApplicationUser>(), It.IsAny<bool>())).Returns(Task.FromResult(true)); 

     var sut = new AccountController(userManagerStub.Object) {SignInManager = signInManagerStub.Object}; 

     // Act 
     var result = await sut.Register(new RegisterViewModel() { Password = "fakePw" }) as RedirectToRouteResult; 

     // Assert 
     Assert.AreEqual<string>("Index", result.RouteValues["action"].ToString()); 
     Assert.AreEqual<string>("Home", result.RouteValues["controller"].ToString()); 
    } 
+0

Raj - спасибо за ввод. Я не могу заставить TestMethod работать (версия NSubstitute). Небольшая точка - там, кажется, есть какой-то код Moq (Mock ). Но я тоже не мог его скомпилировать. Например, первая строка var userManagerStub = Substitute.For >(); говорит, что мне нужна ссылка на сборку для IUserManager, но я не был уверен, что это было. Наконец, можете ли вы дать мне более подробную информацию о том, где я реализую интерфейс ISignInManager. Нужно ли связывать это с помощью Ninject или что-то в этом роде. Извините, если это очевидные вопросы. –

+0

@MikeSmith извините за поздний ответ. Да, была ошибка, я перепутал код moq с NS. Теперь он исправлен в обновленном ответе. IUserManager - это интерфейс, который реализует UserManager. Я просто создал это, не зная, что ваш UserManager является макетным. Если yes вместо IUserManager просто использует UserManager. С ISignInManager, я думаю, у вас есть собственный метод SignInAsync? Этот интерфейс абстрагируется от реализации, и вы можете вводить его через инъекцию свойств. – Spock

+0

Спок - еще раз спасибо, но он все еще не компилируется. Ваше заявление («Я только что создал, что не знаю точно, что ваш UserManager является макетным»), действительно то, что я пытаюсь проверить. Я использую членство по умолчанию, которое поставляется с VS 2013. Как я уже упоминал в своем вопросе - это не работает (var substitute = Substitute.For >();) –

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