web-dev-qa-db-fra.com

Comment attribuer des valeurs aux propriétés dans moq?

J'ai une classe avec une méthode qui retourne un objet de 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 est un objet de domaine. Notez la propriété Id avec 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; }
}

L'ID est protégé car il est généré par la base de données.

Projet de test

Dans mon projet de test, j'ai un faux dépôt avec une méthode Store pour enregistrer/mettre à jour l'objet:

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);
    }
}

Dans CustomMembershipProvider j'ai public override MembershipUser CreateUser méthode qui appelle le GetUser pour créer un User.
De cette façon, tout ce que j'ai à faire est de simuler la méthode GetUser pour que le référentiel puisse générer le 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;

Problème

En théorie, tout est correct. Lorsque CreateUser appelle 'GetUser' pour créer un utilisateur, l'utilisateur renverra Mock rempli;

[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);
}

Le problème est que l'e-mail, le nom et le mot de passe sont vides (avec les valeurs par défaut)!

enter image description here

51
ridermansb

La façon dont vous préparez l'utilisateur simulé est le problème.

moqUser.Object.Name = username;

ne définira pas le nom, sauf si vous avez correctement configuré la maquette. Essayez ceci avant d'attribuer des valeurs aux propriétés:

moqUser.SetupAllProperties();

Cette méthode préparera toutes les propriétés de la maquette pour pouvoir enregistrer la valeur attribuée et la rejouer plus tard (c'est-à-dire pour agir comme une propriété réelle).

Vous pouvez également utiliser la méthode SetupProperty () pour configurer des propriétés individuelles afin de pouvoir enregistrer la valeur transmise.

Une autre approche est:

var mockUser = Mock.Of<User>( m =>
    m.Name == "whatever" &&
    m.Email == "[email protected]"); 

return mockUser;
99
Sunny Milenov

Je pense qu'il vous manque le but de se moquer. Mocks utilisés pour se moquer des dépendances de la classe que vous testez:

enter image description here

Le système testé (SUT) doit être testé isolément (c'est-à-dire séparé des autres unités). Sinon, des erreurs dans les dépendances entraîneront l'échec de vos tests SUT. Vous ne devez pas non plus écrire de tests pour les simulations. Cela ne vous donne rien, car les simulacres ne sont pas du code de production. Les maquettes ne sont pas exécutées dans votre application.

Donc, vous ne devez vous moquer de CustomMembershipProvider que si vous testez une unité, qui en dépend (BTW, il est préférable de créer une abstraction comme l'interface ICustomMembershipProvider en fonction).

Ou, si vous écrivez des tests pour la classe CustomMembershipProvider, alors il ne faut pas la moquer - seules les dépendances de ce fournisseur doivent être moquées.

8