2010-07-17 9 views
107

Imagínese esta claseMoq: Como llegar a un parámetro pasado a un método de un servicio burlado

public class Foo { 

    private Handler _h; 

    public Foo(Handler h) 
    { 
     _h = h; 
    } 

    public void Bar(int i) 
    { 
     _h.AsyncHandle(CalcOn(i)); 
    } 

    private SomeResponse CalcOn(int i) 
    { 
     ...; 
    } 
} 

Mo (q) Handler cking en una prueba de Foo, ¿cómo iba a ser capaz de comprobar lo Bar() ha pasado al _h.AsyncHandle?

+0

¿Querías decir "AsyncHandle" (extra "n")? ¿Y podría publicar el código para Handler o especificar el nombre del tipo completo si es un tipo estándar? – TrueWill

+0

¿Puedes mostrar tu prueba de esqueleto para mostrar lo que estás pensando? Si bien aprecio que por su parte es obvio, por nuestro lado, parece que alguien que no se ha tomado el tiempo para hacer que la pregunta responda sin hacer una respuesta especulativa larga. –

+1

No hay ni un Foo ni un Bar() ni nada de eso. Es solo un código de demostración para mostrar la situación en la que me encuentro sin distracciones de los detalles de las aplicaciones. Y obtuve la respuesta, esperaba obtener. – Jan

Respuesta

178

Se puede utilizar el método de Mock.Callback-:

var mock = new Mock<Handler>(); 
SomeResponse result = null; 
mock.Setup(h => h.AnsyncHandle(It.IsAny<SomeResponse>())) 
    .Callback<SomeResponse>(r => result = r); 

// do your test 
new Foo(mock.Object).Bar(22); 
Assert.NotNull(result); 

Si sólo desea comprobar algo simple en el pasado en el argumento, también puede hacerlo directamente:

mock.Setup(h => h.AnsyncHandle(It.Is<SomeResponse>(response => response != null))); 
+1

perfecto, gracias! – Jan

+14

Una nota al margen, si tiene múltiples argumentos para su función, necesita especificar todos los tipos en el método genérico 'Callback <>()' Moq. Por ejemplo, si tu método tuviera la definición 'Handler.AnsyncHandle (string, SomeResponse)', necesitarías '/ * ... * /. Callback (r => result = r);'. No he encontrado esto explícitamente establecido en muchos lugares, así que pensé que lo agregaría aquí. –

17

Gamlor de la respuesta funciona, pero otra forma de hacerlo (y una que considero más expresiva en la prueba) es ...

var mock = new Mock<Handler>(); 
var desiredParam = 47; // this is what you want to be passed to AsyncHandle 
new Foo(mock.Object).Bar(22); 
mock.Verify(h => h.AsyncHandle(desiredParam), Times.Once()); 

Verificar es muy poderoso, y vale la pena tomarse el tiempo para acostumbrarse.

+9

Este enfoque está bien si solo quieres comprobar si se llamó a un método con un parámetro conocido. En el caso en que el parámetro aún no se haya creado en el momento de escribir la prueba (por ejemplo, la unidad en cuestión crea el parámetro internamente), Callback le permite capturar e interrogar esto, mientras que su enfoque no lo haría. – Michael

+0

Necesito almacenar el valor pasado porque necesito verificar que se pasó todo un conjunto de objetos. – MrFox

1

Puede usar It.Is<TValue>() matcher.

var mock = new Mock<Handler>(); new Foo(mock.Object).Bar(22); mock.Verify(h => h.AsyncHandle(It.Is<SomeResponse>(r => r != null)));

+0

Typo - 'AnsyncHandle' debería ser 'AsyncHandle' –

2

respuesta de Gamlor trabajó para mí, pero yo pensaba que iba a ampliar el comentario de John Carpenter, porque yo estaba buscando una solución que implica más de un parámetro. Pensé que otras personas que tropezarían con esta página podrían estar en una situación similar. Encontré esta información en el Moq documentation.

Usaré el ejemplo de Gamlor, pero supongamos que el método AsyncHandle toma dos argumentos: un string y un objeto SomeResponse.

var mock = new Mock<Handler>(); 
string stringResult = string.Empty; 
SomeResponse someResponse = null; 
mock.Setup(h => h.AsyncHandle(It.IsAny<string>(), It.IsAny<SomeResponse>())) 
    .Callback<string, SomeResponse>((s, r) => 
    { 
     stringResult = s; 
     someResponse = r; 
    }); 

// do your test 
new Foo(mock.Object).Bar(22); 
Assert.AreEqual("expected string", stringResult); 
Assert.IsNotNull(someResponse); 

Básicamente sólo tiene que añadir otro It.IsAny<>() con el tipo apropiado, añadir otro tipo con el método Callback, y cambiar la expresión lambda según corresponda.

Cuestiones relacionadas