6
\$\begingroup\$

I'm new to unit testing and have created a unit test for a create user action method and it's passing the test. I'm not sure if this is the right way to unit test a create method.

This is my test method:

[TestMethod]
public void Create_User()
{
    Mapper.CreateMap<UserViewModel, User>();

    //Arrange
    var membershipRepository = Mock.Create<IStaticMembershipService>();
    var userMock = Mock.Create<MembershipUser>();
    Mock.Arrange(() => userMock.ProviderUserKey).Returns(1);
    Mock.Arrange(() => membershipRepository.GetUser()).Returns(userMock);
    var UserRepository = Mock.Create<IUserRepository>();

    MemoryStream stream = new MemoryStream();
    StreamWriter writer = new StreamWriter(stream);
    writer.Write("Creating Streams for Testing");
    writer.Flush();
    stream.Position = 0;
    var mockFile = Mock.Create<HttpPostedFileBase>();
    Mock.Arrange(() => mockFile.ContentType).Returns("application/pdf");
    Mock.Arrange(() => mockFile.FileName).Returns("Test.pdf");
    Mock.Arrange(() => mockFile.InputStream).Returns(stream);
    Mock.Arrange(() => mockFile.ContentLength).Returns(1);
    UserViewModel mockUserViewModel = new UserViewModel { Description = "TestDesc", Title = "Tester", UserId = 1, File = mockFile };

    Mock.Arrange(() => UserRepository.AddUser(Arg.IsAny<User>())).Returns(new OperationStatus{Status = true});
    //Act
    UserController controller = new UserController(UserRepository, membershipRepository);
    RedirectToRouteResult actionResult = (RedirectToRouteResult)controller.Create(mockUserViewModel);

    //Assert
    Assert.AreEqual(actionResult.RouteValues["Action"], "Index");
}

This is the action method:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(UserViewModel item)
{
    if (ModelState.IsValid)
    {
        var newUser = Mapper.Map<UserViewModel, User>(item);
        //Populates file name and content type to newUser
        UserHelper.PopulateFile(item.File, newUser);

        newUser.UserId = (int)_membershipService.GetUser().ProviderUserKey;

        var opStatus = _UserRepository.AddUser(newUser);
        if (!opStatus.Status)
            throw new System.Web.Http.HttpResponseException(new   HttpResponseMessage(HttpStatusCode.InternalServerError));

        return RedirectToAction("Index");
    }
    else
        return View(item);
}

Any relevant controller info:

private IUserRepository _UserRepository;
private IStaticMembershipService _membershipService;

public UserController(IUserRepository UserRepo, IStaticMembershipService membershipService)
{
    _UserRepository = UserRepo;
    _membershipService = membershipService;
}

IUserRepository:

public interface IUserRepository
{
    List<User> GetAllUsers(int Id);

    OperationStatus AddUser(User newUser);

    User GetUserById(int Id);
}

UserRepository containing definitions of above interfaces:

public List<User> GetAllUsers(int Id)
{
    using (DataContext)
    {
        return DataContext.Users.Where(j => j.Id == Id).ToList();
    }
}

public Journal GetUserById(int Id)
{
    using (DataContext)
        return DataContext.Users.SingleOrDefault(j => j.UserId == Id);
}     

public OperationStatus AddUser(Journal newUser)
{
    var opStatus = new OperationStatus { Status = true };
    try
    {
        using (DataContext)
        {
            newUser.ModifiedDate = DateTime.Now;
            var j = DataContext.Users.Add(newUser);
            DataContext.SaveChanges();
        }
    }
    catch (Exception e)
    {
        //opStatus = OperationStatus.CreateFromException("Error adding user: ", e);
    }

    return opStatus;
}

The test is running fine. I'm just not sure if it's the right way for unit testing. Please let me know if I'm following the right approach here.

\$\endgroup\$
2
\$\begingroup\$

I think you are not testing everything. The API should create a user but the only thing you assert is the ActionResult

Assert.AreEqual(actionResult.RouteValues["Action"], "Index");

So the method runs and the result is correct. But has it actually created a new user and add it to the repository? How about this operation?

var opStatus = _UserRepository.AddUser(newUser);

IMO you should also check the repository to see whether the API correctly added the new user to it. I don't know what interfaces the UserRepository might implement but for this

var UserRepository = Mock.Create<IUserRepository>();

assertions like these ones could be appropriate (just examples) or anything else that makes sense for the repository.

Assert.AreEqual(1, UserRepository.Count);
Assert.AreEqual(referenceUser, UserRepository.GetUser(abc));

What if someone had a problem with the repository and commented it out and actually forgot to add #if DEBUG or made any other changes ignoring the status-code?

public ActionResult Create(UserViewModel item)
{
    if (ModelState.IsValid)
    {
        var newUser = Mapper.Map<UserViewModel, User>(item);
        //Populates file name and content type to newUser
        UserHelper.PopulateFile(item.File, newUser);

        newUser.UserId = (int)_membershipService.GetUser().ProviderUserKey;

        // I temporarily disabled the repository because I didn't work for me.
        //var opStatus = _UserRepository.AddUser(newUser);
        //if (!opStatus.Status)
        //    throw new System.Web.Http.HttpResponseException(new   HttpResponseMessage(HttpStatusCode.InternalServerError));

        return RedirectToAction("Index");
    }
    else
        return View(item);
}

The test would still pass but the result would be wrong.

\$\endgroup\$
  • \$\begingroup\$ Are you saying that I need to insert a new user in database to test the create method. Is it possible inserting a new record in DB while testing? Will it be appropriate.? I have updated the code structure for IUserRepository and UserRepository in my question above. Can you now show me how proper testmethod for create method will be made? \$\endgroup\$ – Satvinder Singh Jun 13 '17 at 11:51
  • \$\begingroup\$ @SatvinderSingh Are you saying that I need to insert a new user in database - not exactly, I mean it woudl be enough to verfiy that the Create API called the AddUser method and actually tried to add the new user to it. You have a mock for it var UserRepository = Mock.Create<IUserRepository>(); - with it, it should be possible to check if AddUser was actually called and what was added. \$\endgroup\$ – t3chb0t Jun 13 '17 at 13:29
  • \$\begingroup\$ @SatvinderSingh I need to correct myself, you should not check if the AddUser method was actually called, because this API might change but rather that after calling Create there is one more new user in the repository and because it's an abstraction you should easily be able to achieve this. \$\endgroup\$ – t3chb0t Jun 13 '17 at 13:39
  • \$\begingroup\$ Can you show me how it can be done? I don't know how to proceed here \$\endgroup\$ – Satvinder Singh Jun 15 '17 at 12:11
  • \$\begingroup\$ @SatvinderSingh unfortuantelly not, I don't know JustMock at all but you wrote such good test already so you should be able to write one more assert too ;-) \$\endgroup\$ – t3chb0t Jun 15 '17 at 12:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.