78

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.

Test project

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;

Problem

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)!

enter image description here

Community
  • 1
  • 1
ridermansb
  • 10,779
  • 24
  • 115
  • 226
  • Which class you are testing here? I see only mocks around – Sergey Berezovskiy May 29 '13 at 14:31
  • 1
    I'm testing my `CustomMembershipProvider`. `status.Should().Be(MembershipCreateStatus.Success);` In the repository, the user created with e-mail, name and password empty. – ridermansb May 29 '13 at 14:35
  • `CustomMembershipProvider` is a mock in your code. You are testing moq framework? – Sergey Berezovskiy May 29 '13 at 14:37
  • 1
    @SergeyBerezovskiy `CustomMembershipProvider` is a mock because he mocks one method on this class, but nevertheless calls the base implementation for every other method (because of `.CallBase = true`) – bvgheluwe Sep 05 '16 at 11:17

3 Answers3

148

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 == "someone@example.com"); 

return mockUser;
CryptoFool
  • 21,719
  • 5
  • 26
  • 44
Sunny Milenov
  • 21,990
  • 6
  • 80
  • 106
11

I think you are missing purpose of mocking. Mocks used to mock dependencies of class you are testing:

enter image description here

System under test (SUT) should be tested in isolation (i.e. separate from other units). Otherwise errors in dependencies will cause your SUTs tests to fail. Also you should not write tests for mocks. That gives you nothing, because mocks are not production code. Mocks are not executed in your application.

So, you should mock CustomMembershipProvider only if you are testing some unit, which depends on it (BTW it's better to create some abstraction like interface ICustomMembershipProvider to depend on).

Or, if you are writing tests for CustomMembershipProvider class, then it should not be mocked - only dependencies of this provider should be mocked.

Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • 1
    In theory, you are right. Unless the method under test calls another virtual method on the same class, where CallBase = true comes into play. I agree this is bad design to start with, but sometimes people work with legacy code, etc. – Sunny Milenov May 29 '13 at 15:47
  • @SunnyMilenov sorry, but in practice I never test mocks. Is there any examples when testing mock can be useful? – Sergey Berezovskiy May 29 '13 at 17:01
  • 1
    @lazyberezovsky excellent explanation. And I agree with you. In this particular case I test `CustomMembershipProvider`, specifically the creation of users: `CreateUser` method .. – ridermansb May 29 '13 at 17:31
  • .. Inside the `CreateUser` method, an object `User` is created call `GetUser` method. But the `Id` property of my `User` object a setter is as protected (*Id is generated by the database*)... – ridermansb May 29 '13 at 17:33
  • **How can I test my class** `CustomMembershipProvider`? I need mock my domain object `User` So Id is always `.Max(p => p.Id) + 1` – ridermansb May 29 '13 at 17:34
  • 2
    @lzayberezovsky: in this concrete example he is not testing the mock, but CustomMembershipProviderClass. He just uses moq as a helper to let him override one particular method of it, instead of creating an inherited class, and override there. In this case, this is not a mock, but stub. – Sunny Milenov May 29 '13 at 18:19
  • @ridermansb If you only need to get your own Id during user creation, then you should probably mock the database as this is the place where the Id is created. – SalgoMato Aug 04 '18 at 12:03
2

Specifies that the all properties on the mock should have "property behavior", meaning that setting their value will cause them to be saved and later returned when the properties is requested. (This is also known as "stubbing".) The default value for each property will be the one generated as specified by the property for the mock.

mock.SetupAllProperties();
Amir Touitou
  • 3,141
  • 1
  • 35
  • 31