2011-06-08 16 views
14

El escenario es el siguiente: un usuario realiza alguna acción (como ganar una insignia o desbloquear algo) y se envía una notificación por correo electrónico. Una para el usuario (con un mensaje como "Has desbloqueado XYZ ...") y luego un mensaje diferente para cada uno de sus amigos como ("Tu amigo ha desbloqueado XYZ ...").Cómo verificar varias llamadas a métodos con Moq

public interface INotify 
{ 
    void Notify(User user, User friend); 
} 

public class NotificationService 
{ 
    private IEnumerable<INotify> _notifiers; 

    public NotificationService(IEnumerable<INotify> notifiers) 
    { 
     _notifiers = notifiers; 
    } 

    public SendNotifications() 
    { 
     User user = GetUser(); 
     IEnumerable<User> friends = GetFriends(); 

     foreach(var notifier in _notifiers) 
     { 
      //Send notification to user 
      notifier.Notify(user, null); 

      //send notification to users friends 
      foreach(var friend in friends) 
       notifier.Notify(user, friend); 
     } 
    } 
} 

Estoy tratando de usar moq para probar que cada notificador se llama 2x. Una vez pasando null como el segundo parámetro y la segunda vez pasando un valor a ambos parámetros.

[Test] 
public void MakeSureEveryoneIsNotified() 
{ 
    var notifierMock = new Mock<INotifier>(); 

    var svc = new NotificationService(new List<INotifier>{ notifierMock.Object });  
    svc.SendNotifications(); 

    notifierMock.Verify(x => x.Notify(It.Is<User>(user => user.UserId == 1), null), Times.Once()); 
    notifierMock.Verify(x => x.Notify(It.Is<User>(user => user.UserId == 1), It.Is<User>(user => user.UserId == 2)), Times.Once()); 
} 

El problema es que la segunda llamada de verificación arroja una ArgumentNullException para el segundo parámetro. ¿Hay algo que decir "Compruebe que la primera llamada tiene estos parámetros, y luego la segunda llamada tiene otros parámetros". Sé que puedo solucionarlo simplemente llamando al:

notifierMock.Verify(x => x.Notify(It.IsAny<User>(), It.IsAny<User>()), Times.Exactly(2)); 

Pero quería ser un poco más específico. ¿Alguna forma de hacer esto?

+0

¿Ha intentado recrear a un Usuario fuera de la declaración .Verify y usar ese Usuario como argumento? –

+0

Quitaría la dependencia del método GetUser(), crearía un proveedor de usuario, se burlaría de él y luego uniría las partes relevantes del proveedor. –

+0

El método GetUser es realmente de una dependencia externa que se inyecta en la clase, pero lo dejé para abreviar. La primera opción debería funcionar – Micah

Respuesta

18

Puede lograr esto registrando lo que sucede en cada llamada al Notify. Luego puede comparar la grabación con lo que se espera:

[TestMethod] 
public void TestMoqInvocations() 
{ 
    var notifierMock = new Mock<INotifier>(); 

    var svc = new NotificationService(new List<INotifier>{ notifierMock.Object });  
    svc.SendNotifications(); 

    var invocations = new List<NotifyParams>(); 

    notifierMock 
     .Setup(f => f.Notify(It.IsAny<User>(), It.IsAny<User>())) 
     .Callback<string, string>((user, friend) => invocations.Add(new NotifyParams{user = user, friend = friend})); 

    Assert.AreEqual(1, invocations[0].user.UserId); 
    Assert.IsNull(invocations[0].friend); 
    Assert.AreEqual(1, invocations[1].user.UserId); 
    Assert.AreEqual(2, invocations[1].user.UserId); 
} 

public struct NotifyParams { 
    public User user {get;set;} 
    public User friend { get; set; } 
} 
Cuestiones relacionadas