Identification of the primary identifier Asp.net unit test

I have a problem with how and what to test.

I have a controller that enters a UserManager and calls the CreateAsync method to create a new user.

I do not want to test the Identity user manager, as this has certainly been thoroughly tested. What I would like to do is check that the controller works through the correct paths (in my case there are three paths, sending replies with model state errors, identifier response errors or a simple string)

Should I try to create a user manager layout to create my test (I'm not sure how to configure the user manager as a dependency on mock) Secondly, how can I set the conditions for checking that the controller has accepted the given path.

I use xUnit and Moq.

 [Route("api/[controller]")] public class MembershipController : BaseApiController { private UserManager<ApplicationUser> _userManager; public MembershipController(UserManager<ApplicationUser> userManager) { _userManager = userManager; } [HttpGet("RegisterNewUser")] public HttpResponseMessage RegisterNewUser([FromBody] NewUserRegistration user) { if (ModelState.IsValid) { ApplicationUser newUser = new ApplicationUser(); newUser.UserName = user.username; newUser.Email = user.password; IdentityResult result = _userManager.CreateAsync(newUser, user.password).Result; if (result.Errors.Count() > 0) { var errors = new IdentityResultErrorResponse().returnResponseErrors(result.Errors); return this.WebApiResponse(errors, HttpStatusCode.BadRequest); } } else { var errors = new ViewModelResultErrorResponse().returnResponseErrors(ModelState); return this.WebApiResponse(errors, HttpStatusCode.BadRequest); } return this.WebApiResponse( "We have sent a valifation email to you, please click on the verify email account link.", HttpStatusCode.OK); } } 

In My unit test I have the following to test the Bon Voyage scenario

  [Fact] public void RegisterNewUser_ReturnsHttpStatusOK_WhenValidModelPosted() { var mockStore = new Mock<IUserStore<ApplicationUser>>(); var mockUserManager = new Mock<UserManager<ApplicationUser>>(mockStore.Object, null, null, null, null, null, null, null, null); ApplicationUser testUser = new ApplicationUser { UserName = " user@test.com " }; mockStore.Setup(x => x.CreateAsync(testUser, It.IsAny<CancellationToken>())) .Returns(Task.FromResult(IdentityResult.Success)); mockStore.Setup(x => x.FindByNameAsync(testUser.UserName, It.IsAny<CancellationToken>())) .Returns(Task.FromResult(testUser)); mockUserManager.Setup(x => x.CreateAsync(testUser).Result).Returns(new IdentityResult()); MembershipController sut = new MembershipController(mockUserManager.Object); var input = new NewUserInputBuilder().Build(); sut.RegisterNewUser(input); } 

Where "enter" in sut.RegisterNewUser (input); refers to a helper class that builds the view model that the controller action requires:

 public class NewUserInputBuilder { private string username { get; set; } private string password { get; set; } private string passwordConfirmation { get; set; } private string firstname { get; set; } private string lastname { get; set; } internal NewUserInputBuilder() { this.username = " user@test.com "; this.password = "password"; this.passwordConfirmation = "password"; this.firstname = "user"; this.lastname = "name"; } internal NewUserInputBuilder WithNoUsername() { this.username = ""; return this; } internal NewUserInputBuilder WithMisMatchedPasswordConfirmation() { this.passwordConfirmation = "MismatchedPassword"; return this; } internal NewUserRegistration Build() { return new NewUserRegistration { username = this.username, password = this.password, passwordConfirmation = this.passwordConfirmation, firstname = this.firstname, lastname = this.lastname }; } } 

My goal is to force three conditions through tests:

  • Create a valid view model and return a successful message
  • Create a valid view model, but returns an IdentityResponse error (for example, the user exists), which translates to
  • Create an invalid view model and return Modelstate errors

Errors are handled using an abstract class that returns a json object. The base class for the controller simply creates an HttpResponseMessage to return.

Basically, I want to verify that the correct error response class is called by forcing the test to test on the modelstate error path, the identityresult.errors path, and achieving a happy path.

My plan then is to isolate the error response classes.

I hope this is enough.

+5
source share
1 answer

Mehod testing should be performed by async and not use blocking calls, i.e. .Result

 [HttpGet("RegisterNewUser")] public async Task<HttpResponseMessage> RegisterNewUser([FromBody] NewUserRegistration user) { if (ModelState.IsValid) { var newUser = new ApplicationUser() { UserName = user.username, Email = user.password }; var result = await _userManager.CreateAsync(newUser, user.password); if (result.Errors.Count() > 0) { var errors = new IdentityResultErrorResponse().returnResponseErrors(result.Errors); return this.WebApiResponse(errors, HttpStatusCode.BadRequest); } } else { var errors = new ViewModelResultErrorResponse().returnResponseErrors(ModelState); return this.WebApiResponse(errors, HttpStatusCode.BadRequest); } return this.WebApiResponse( "We have sent a valifation email to you, please click on the verify email account link.", HttpStatusCode.OK); } 

An overview of the Happy Path script and method that is being tested shows that there is no need to configure UserStore , since the test will directly overlap the virtual members of the user manager.

Note that the test was also run as asynchronous.

  • Create a valid view model and return a successful message
 [Fact] public async Task RegisterNewUser_ReturnsHttpStatusOK_WhenValidModelPosted() { //Arrange var mockStore = Mock.Of<IUserStore<ApplicationUser>>(); var mockUserManager = new Mock<UserManager<ApplicationUser>>(mockStore, null, null, null, null, null, null, null, null); mockUserManager .Setup(x => x.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>())) .ReturnsAsync(IdentityResult.Success); var sut = new MembershipController(mockUserManager.Object); var input = new NewUserInputBuilder().Build(); //Act var actual = await sut.RegisterNewUser(input); //Assert actual .Should().NotBeNull() .And.Match<HttpResponseMessage>(_ => _.IsSuccessStatusCode == true); } 
  1. Create a valid view model, but returns an IdentityResponse error (e.g. user exists) that is being converted

To do this, you just need to customize the layout to return the result with errors.

 [Fact] public async Task RegisterNewUser_ReturnsHttpStatusBadRequest_WhenViewModelPosted() { //Arrange //...code removed for brevity mockUserManager .Setup(x => x.CreateAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>())) .ReturnsAsync(IdentityResult.Failed(new IdentityError { Description = "test"})); //...code removed for brevity //Assert actual .Should().NotBeNull() .And.Match<HttpResponseMessage>(_ => _.StatusCode == HttpStatusCode.BadRequest); } 

And for

  1. Create an invalid view model and return Modelstate errors

You just need to set the state of the controller model so that it is invalid.

 [Fact] public async Task RegisterNewUser_ReturnsHttpStatusBadRequest_WhenInvalidModelState() { //Arrange var mockStore = Mock.Of<IUserStore<ApplicationUser>>(); var mockUserManager = new Mock<UserManager<ApplicationUser>>(mockStore, null, null, null, null, null, null, null, null); var sut = new MembershipController(mockUserManager.Object); sut.ModelState.AddModelError("", "invalid data"); var input = new NewUserInputBuilder().Build(); //Act var actual = await sut.RegisterNewUser(input); //Assert actual .Should().NotBeNull() .And.Match<HttpResponseMessage>(_ => _.StatusCode == HttpStatusCode.BadRequest); } 

FluentAssertions were used to complete all statements. You could easily use the Assert.* API.

This should be enough to help you resolve the above issue.

0
source

Source: https://habr.com/ru/post/1273464/


All Articles