2017-05-12 1 views
1

J'utilise Moq pour se moquer de mes objets dans un projet de base Aspnet.Comment se moquer de IMongoDatabase

Je veux railler la méthode IsConnection() suivant:

public Client(IMongoClient client) 
{ 
    _client = client; 
} 

public async Task<bool> IsConectionOk() 
{    
    var pingCommand = new BsonDocument("ping", 1); 
    var mongoDb = _client.GetDatabase("Name"); 
    var commandResult = await mongoDb.RunCommandAsync<BsonDocument>(pingCommand); 
    return commandResult != null;   
} 

Comme vous le voyez, il n'y a qu'une seule injection, IMongoClient, donc je dois se moquer de celui-ci. Maintenant, je dois moquer IMongoDatabase aussi bien depuis le _client.GetDatabase me retourne un IMongoDatabase qui court RunCommandAsync

ceci est mon test unitaire:

[Fact] 
public async Task IsConnectionOk_xxx_RunPing1Command() 
{ 
    var dbMock = new Mock<IMongoDatabase>(); 
    var resultCommand = new BsonDocument("ok", 1); 
    dbMock.Setup(stub => stub.RunCommandAsync<BsonDocument>(It.IsAny<BsonDocument>(), It.IsAny<ReadPreference>(), It.IsAny<CancellationToken>())).ReturnsAsync(resultCommand); 

    var mongoClientMock = new Mock<IMongoClient>(); 
    mongoClientMock.Setup(stub => stub.GetDatabase(It.IsAny<string>(), It.IsAny<MongoDatabaseSettings>())).Returns(dbMock.Object); 

    var client = new Client(mongoClientMock.Object); 
    var pingCommand = new BsonDocument("ping", 1); 

    //act 
    await client.IsConectionOk(); 

    //assert 
    dbMock.Verify(mock => mock.RunCommandAsync<BsonDocument>(It.Is<BsonDocument>(x => x.Equals(pingCommand)) , It.IsAny<ReadPreference>() ,It.IsAny<CancellationToken>())); 
} 

Vous pouvez voir que je moquais un IMongoDataba donc mon mongoClientMock peut retourner lorsque le code est en cours d'exécution. Lorsque le code est en cours d'exécution, je l'ai vérifié que mongoClientMock.GetDatabase() est un retour MongoDatabase (bon jusqu'à ce qu'il y), le problème est que lorsque MongoDatabaseMock appels RunCommandAsync ne retourne pas ce que je mis en place, il retourne juste null. Je ne sais pas ce que je pourrais manquer ici, des pensées?

+0

Vérifiez également ne pas fonctionner car ils ont des instances différentes. – Nkosi

+0

@Nkosi aussi, que vouliez-vous dire par 'Vérifiez ne fonctionnera pas'? Mon mongoClientMock.GetDatabase() devrait renvoyer dbMock qui est configuré au début du test donc c'est la même instance, ai-je oublié quelque chose? – monkeyBug

+0

Vous initialisez une commande en dehors de la méthode testée et essayez de vérifier qu'elle (l'instance) a été utilisée dans le simulacre. cette vérification échouera. – Nkosi

Répondre

1

Les choses sont un peu difficiles ici.

Quelques informations d'abord.

Selon la documentation, IMongoDatabase.RunCommandAsync<TResult> est définie comme

Task<TResult> RunCommandAsync<TResult>(
    Command<TResult> command, 
    ReadPreference readPreference = null, 
    CancellationToken cancellationToken = null 
) 

Notez le Command<TResult>, alors que dans votre code que vous passez un BsonDocument.

Heureusement BsonDocument a un opérateur de conversion implicite BsonDocument-Command<TResult>

Lorsqu'une installation ne reçoit pas ce qui a été configuré, il a tendance à revenir nulle. Donc, vous devez vous assurer qu'il est configuré correctement afin qu'il effectue le comportement attendu.

[TestClass] 
public class UnitTest1 { 
    [TestMethod] 
    public async Task _IsConnectionOk_xxx_RunPing1Command() { 
     var dbMock = new Mock<IMongoDatabase>(); 
     var resultCommand = new BsonDocument("ok", 1); 
     dbMock 
      .Setup(stub => stub.RunCommandAsync<BsonDocument>(It.IsAny<Command<BsonDocument>>(), It.IsAny<ReadPreference>(), It.IsAny<CancellationToken>())) 
      .ReturnsAsync(resultCommand) 
      .Verifiable(); 

     var mongoClientMock = new Mock<IMongoClient>(); 
     mongoClientMock 
      .Setup(stub => stub.GetDatabase(It.IsAny<string>(), It.IsAny<MongoDatabaseSettings>())) 
      .Returns(dbMock.Object); 

     var client = new Client(mongoClientMock.Object); 
     var pingCommand = new BsonDocument("ping", 1); 

     //act 
     var actual = await client.IsConectionOk(); 

     //assert 
     Assert.IsTrue(actual); 
     dbMock.Verify(); 
    } 
} 
1

Je viens de trouver mon problème, jetez un oeil à la ligne suivante:

dbMock.Setup(stub => stub.RunCommandAsync<BsonDocument>(It.IsAny<BsonDocument>(), It.IsAny<ReadPreference>(), It.IsAny<CancellationToken>())).ReturnsAsync(resultCommand); 

se avère que RunCommandAsync premier paramètre est un Command<TResult> si le correctif je avais besoin était:

dbMock.Setup(stub => stub.RunCommandAsync<BsonDocument>(It.IsAny<Command<BsonDocument>>(), It.IsAny<ReadPreference>(), It.IsAny<CancellationToken>())).ReturnsAsync(anyResultCommand); 

Et le problème est résolu !