web-dev-qa-db-fra.com

Moq simule une méthode mais utilise une implémentation réelle d'une autre

Étant donné une interface IService qui a Method1() et Method2().

Je veux tester que lorsque Method1() lance un Exception, Method2() Est appelé et retourne une valeur donnée.

(Method2() est appelée lorsque Method1() lance).

J'ai donc besoin de tester une vraie Method2() avec une fausse Method1(), ce sont des méthodes de la même interface.

Voici mon code de test:

MBase sut.MethodX() est le seul point d'entrée. Il utilise IService.

Mon objectif est d'affirmer que Method2() renvoie quelque chose .

// Arrange
// Fake bytes in.
var networkStreamMock = new Mock<INetworkStream>();
networkStreamMock.Method1(x => x.Read(It.IsAny<byte[]>(), It.IsAny<int>(), It.IsAny<int>())).Returns(It.IsAny<byte[]>());

// Force throw TimeoutException.
var mock = new Mock<IService>();
mock.Setup(x => x.Method1(new Message
{ 
    Xml = Xml,  
}
)).Throws<TimeoutException>();

// Check Method 2 is called. (this is done in its own test so commented out)
// mock.Setup(m => m.Method2(It.IsAny<Message>())).Verifiable();

// New MBase.
IKernel kernel = new StandardKernel(new FakeBindings());
kernel.Rebind<IService>().ToConstant(mock.Object);
MBase sut = kernel.Get<M>();

// Act
sut.MethodX(networkStreamMock.Object);

// Here I would like to assert on the return value of Method2
mock.Verify(m => m.Method2(It.IsAny<Message>()));

Est-ce possible avec Moq ou un autre cadre de simulation? Comment fait-on ça? Je peux créer une maquette manuelle avec une fausse implémentation de Method1() et une vraie implémentation de Method2() mais je me demande s'il y a une meilleure approche.

J'ai déjà testé IService isolément mais je souhaite maintenant tester son interaction avec MBase.

37
Sam Leach

Vous pouvez le faire avec:

var mock = new Mock<MyNetworkStream>(){ CallBase = true };
mock.Setup(m => m.Method1....

Le code ci-dessus utilisera l'implémentation réelle de MyNetworkStream pour toute méthode/propriété qui n'est pas explicitement configurée. C'est à dire. il appellera la vraie méthode2 (), tandis que la méthode1 () sera la version simulée.

CallBase=true est généralement destiné à tester des classes abstraites (si cela est correct ou incorrect, est hors de portée de cette question).

60
Sunny Milenov

Dans ce cas (sauf s'il y en a beaucoup plus), je créerais simplement ma propre classe de test étendant la classe avec le comportement réel, qui implémente l'interface dont vous avez besoin de vous moquer. De cette façon, vous pouvez vous moquer de la valeur unique et revenir à la classe de base pour la fonctionnalité réelle.

8
Chris Missal