I have a class with a method that returns an object of type User
public class CustomMembershipProvider : MembershipProvider { public virtual User GetUser(string username, string password, string email, bool isApproved) { return new User() { Name = username ,Password = EncodePassword(password) ,Email = email ,Status = (isApproved ? UsuarioStatusEnum.Ativo : UsuarioStatusEnum.ConfirmacaoPendente) // ... }; } // .. }
User
is a domain object. Note the Id
property with setter as protected:
public class User : IAuditable, IUser { public virtual int Id { get; protected set; } public virtual string Name { get; set; } public virtual string Email { get; set; } public virtual UsuarioStatusEnum Status { get; set; } public virtual string Password { get; set; } }
Id is protected because it is generated by the database.
In my Test project I have a Fake repository with a method Store
to save/update the object:
public void Store(T obj) { if (obj.Id > 0) _context[obj.Id] = obj; else { var generateId = _context.Values.Any() ? _context.Values.Max(p => p.Id) + 1 : 1; var stubUser = Mock.Get<T>(obj); // In test, will always mock stubUser.Setup(s => s.Id).Returns(generateId); _context.Add(generateId, stubUser.Object); } }
In CustomMembershipProvider
I have public override MembershipUser CreateUser
method that calls the GetUser
to create a User
.
This way, all I have to do is mock the GetUser
method so that the repository can generate the Id
var membershipMoq = new Mock<CustomMembershipProvider>(); membershipMoq.CallBase = true; membershipMoq .Setup(p => p.GetUser(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>())) .Returns<string, string, string, bool>( (username, password, email, isAproved) => { var moqUser = new Mock<User>(); moqUser.Object.Name = username; moqUser.Object.Password = password; moqUser.Object.Email = email; moqUser.Object.Status = (isAproved ? UsuarioStatusEnum.Ativo : UsuarioStatusEnum.ConfirmacaoPendente); return moqUser.Object; }); _membershipProvider = membershipMoq.Object;
In theory everything is correct. When CreateUser
call 'GetUser' to create a user, the user will return Mock filled;
[TestMethod] public void CreateUser_deve_criar_usuario_no_repositorio() { // Act MembershipCreateStatus status; var usr = _membershipProvider.CreateUser( _fixture.Create<string>(), _fixture.Create<string>(), _fixture.Create<string>(), null, null, true, null, out status); // usr should have name, email password filled. But not! // Assert status.Should().Be(MembershipCreateStatus.Success); }
The problem is that Email, Name, Password are empty (with default values)!
Unit testing is a powerful way to ensure that your code works as intended. It's a great way to combat the common “works on my machine” problem. Using Moq, you can mock out dependencies and make sure that you are testing the code in isolation.
You can use Moq to create mock objects that simulate or mimic a real object. Moq can be used to mock both classes and interfaces. However, there are a few limitations you should be aware of. The classes to be mocked can't be static or sealed, and the method being mocked should be marked as virtual.
Moq is a mocking framework built to facilitate the testing of components with dependencies. As shown earlier, dealing with dependencies could be cumbersome because it requires the creation of test doubles like fakes. Moq makes the creation of fakes redundant by using dynamically generated types.
The way you prepare the mocked user is the problem.
moqUser.Object.Name = username;
will not set the name, unless you have setup the mock properly. Try this before assigning values to properties:
moqUser.SetupAllProperties();
This method will prepare all properties on the mock to be able to record the assigned value, and replay it later (i.e. to act as real property).
You can also use SetupProperty() method to set up individual properties to be able to record the passed in value.
Another approach is:
var mockUser = Mock.Of<User>( m => m.Name == "whatever" && m.Email == "[email protected]"); return mockUser;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With