2012-06-30 9 views
16

He tenido algunas ocasiones en que algo como esto sería útil. Tengo, por ejemplo, un AccountCreator con un método Create que toma un NewAccount. Mi AccountCreator tiene un IRepository que eventualmente se usará para crear la cuenta. Mi AccountCreator primero mapeará las propiedades de NewAccount a Account, segundo pase el Account al repositorio para finalmente crearlo. Mis pruebas buscan algo como esto:¿Cómo se usa moq para verificar que se haya pasado un objeto similar como argumento?

public class when_creating_an_account 
{ 
    static Mock<IRepository> _mockedRepository; 
    static AccountCreator _accountCreator; 
    static NewAccount _newAccount; 
    static Account _result; 
    static Account _account; 

    Establish context =() => 
     { 
      _mockedRepository = new Mock<IRepository>(); 
      _accountCreator = new AccountCreator(_mockedRepository.Object); 

      _newAccount = new NewAccount(); 
      _account = new Account(); 

      _mockedRepository 
       .Setup(x => x.Create(Moq.It.IsAny<Account>())) 
       .Returns(_account); 
     }; 

    Because of =() => _result = _accountCreator.Create(_newAccount); 

    It should_create_the_account_in_the_repository =() => _result.ShouldEqual(_account); 
} 

Por lo tanto, lo que necesito es algo para reemplazar It.IsAny<Account>, porque eso no ayuda a verificar que la cuenta correcta fue creado. Lo que sería sorprendente es algo así como ...

public class when_creating_an_account 
{ 
    static Mock<IRepository> _mockedRepository; 
    static AccountCreator _accountCreator; 
    static NewAccount _newAccount; 
    static Account _result; 
    static Account _account; 

    Establish context =() => 
     { 
      _mockedRepository = new Mock<IRepository>(); 
      _accountCreator = new AccountCreator(_mockedRepository.Object); 

      _newAccount = new NewAccount 
       { 
        //full of populated properties 
       }; 
      _account = new Account 
       { 
        //matching properties to verify correct mapping 
       }; 

      _mockedRepository 
       .Setup(x => x.Create(Moq.It.IsLike<Account>(_account))) 
       .Returns(_account); 
     }; 

    Because of =() => _result = _accountCreator.Create(_newAccount); 

    It should_create_the_account_in_the_repository =() => _result.ShouldEqual(_account); 
} 

Aviso Me cambió It.IsAny<> a It.IsLike<> y se pasa en un objeto Account poblada. Idealmente, en el fondo, algo compararía los valores de la propiedad y lo dejaría pasar si todos coinciden.

Entonces, ¿ya existe? ¿O podría ser algo que hayas hecho antes y no te importaría compartir el código?

+1

Moq apoya comparadores personalizados - como en, puede tener comparadores personalizados usa cuando se compara argumentos para una llamada , pero tienes que implementarlo tú mismo. Vea el ejemplo [aquí] (http://stackoverflow.com/a/10300051/343266). –

Respuesta

20

Para apagar un repositorio para devolver un valor particular en base a criterios como, el siguiente debería funcionar:

_repositoryStub 
    .Setup(x => x.Create(
     Moq.It.Is<Account>(a => _maskAccount.ToExpectedObject().Equals(a)))) 
    .Returns(_account); 
+0

¡Ahora, ESO era lo que estaba buscando! Gracias Derek! –

+3

En caso de que alguien haya tropezado con esta respuesta y quiera probar lo mismo, debe incluir la biblioteca ExpectedObjects. https://github.com/derekgreer/expectedObjects o 'install-package ExpectedObjects' –

12

El siguiente debe funcionar para usted:

Moq.It.Is<Account>(a=>a.Property1 == _account.Property1) 

Sin embargo, como se mencionó hay que aplicar los criterios de correspondencia.

+0

Lo uso todos los días. Pero imagine que "a" es una clase con 50 propiedades. Preferiría poder utilizar el patrón de objetos esperado para comparar el objeto real (con todas sus propiedades) con un objeto esperado (con todas sus propiedades esperadas). Eso es por lo que estoy esperando. –

0

No he podido encontrar nada que haga exactamente lo que se describe en la pregunta. Mientras tanto, la mejor manera que puedo encontrar para manejar la verificación de objetos pasados ​​como argumentos a métodos burlados (sin el lujo de la igualdad de referencia) es una combinación de Callback y el patrón de Objeto Esperado para comparar el objeto real con el esperado:

public class when_creating_an_account 
{ 
    static Mock<IRepository> _mockedRepository; 
    static AccountCreator _accountCreator; 
    static NewAccount _newAccount; 
    static Account _result; 
    static Account _expectedAccount; 
    static Account _actualAccount; 

    Establish context =() => 
     { 
      _mockedRepository = new Mock<IRepository>(); 
      _accountCreator = new AccountCreator(_mockedRepository.Object); 

      _newAccount = new NewAccount 
       { 
        //full of populated properties 
       }; 
      _expectedAccount = new Account 
       { 
        //matching properties to verify correct mapping 
       }; 

      _mockedRepository 
       .Setup(x => x.Create(Moq.It.IsAny<Account>(_account))) 
       //here, we capture the actual account passed in. 
       .Callback<Account>(x=> _actualAccount = x) 
       .Returns(_account); 
     }; 

    Because of =() => _result = _accountCreator.Create(_newAccount); 

    It should_create_the_account_in_the_repository = 
     () => _result.ShouldEqual(_account); 

    It should_create_the_expected_account = 
     () => _expectedAccount.ToExpectedObject().ShouldEqual(_actualAccount); 
} 

El patrón de objeto esperado es grande, pero esto es complicado de implementar en C#, así que usar una biblioteca que se encarga de todo lo que para mí. https://github.com/derekgreer/expectedObjects

Mi última observación se centra en las propiedades de la cuenta real transferida y las compara con la misma propiedad en mi "objeto esperado". De esta forma, no tengo una gran lista de controles de propiedad simulados, ni tengo muchas observaciones de prueba.

Cuestiones relacionadas