2010-05-01 8 views
27

Estoy burlando de mi interfaz de repositorio y no estoy seguro de cómo configurar un método que toma una expresión y devuelve un objeto? Estoy usando Moq y NUnitMoq.Mock <T> - cómo configurar un método que toma una expresión

Interfaz:

public interface IReadOnlyRepository : IDisposable 
{ 
    IQueryable<T> All<T>() where T : class; 
    T Single<T>(Expression<Func<T, bool>> expression) where T : class; 
} 

prueba con IQueryable ha preparado todavía, pero no saben cómo configurar el T Individual:

private Moq.Mock<IReadOnlyRepository> _mockRepos; 
private AdminController _controller; 
[SetUp] 
public void SetUp() 
{ 
    var allPages = new List<Page>(); 
    for (var i = 0; i < 10; i++) 
    { 
     allPages.Add(new Page { Id = i, Title = "Page Title " + i, Slug = "Page-Title-" + i, Content = "Page " + i + " on page content." }); 
    } 
    _mockRepos = new Moq.Mock<IReadOnlyRepository>(); 
    _mockRepos.Setup(x => x.All<Page>()).Returns(allPages.AsQueryable()); 
    //Not sure what to do here??? 
    _mockRepos.Setup(x => x.Single<Page>() 
    //---- 
    _controller = new AdminController(_mockRepos.Object); 
} 

Respuesta

37

Usted puede configurarlo como esto:

_mockRepos.Setup(x => x.Single<Page>(It.IsAny<Expression<Func<Page, bool>>>()))//.Returns etc...; 

Sin embargo vienes contra uno de los defectos de Moq. Debería poner una expresión real allí en lugar de usar It.IsAny, pero Moq no admite la configuración de métodos que toman expresiones con expresiones específicas (es una función difícil de implementar). La dificultad proviene de tener que averiguar si dos expresiones son equivalentes.

Así que en su prueba que puede pasar en cualquier Expression<Func<Page,bool>> y va a pasar de nuevo a lo que ha configurado la maqueta para volver. El valor de la prueba está un poco diluido.

+1

Gracias por la respuesta. Estoy obteniendo el error con el código anterior: Error Argumento '1': no ​​se puede convertir de 'grupo de métodos' a 'System.Linq.Expressions.Expression > – Paul

+0

@Paul: Lo siento, dejé caer '()'. Pruebe con la última versión y debería funcionar. –

+0

Gracias por la respuesta, que funcionó, no ideal como usted mencionó, ¡pero funciona! Gracias de nuevo. – Paul

6

Haga que la llamada .Returns devuelva el resultado de la expresión contra su variable allPages.

_mockRepos.Setup(x => x.Single<Page>(It.IsAny<Expression<Func<Page, bool>>>())) 
    .Returns((Expression<Func<Page, bool>> predicate) => allPages.Where(predicate)); 
1

El uso de It.IsAny<> sin un .CallBack te obliga a escribir código que no está cubierto por su prueba Moq. En cambio, permite que cualquier consulta/expresión pase, haciendo que tu simulacro sea básicamente inútil desde una perspectiva de prueba de unidad.

La solución: o necesita utilizar una Devolución de llamada para probar la expresión O necesita restringir su simulacro mejor. De cualquier manera es complicado y difícil. He tratado este tema mientras he estado practicando TDD. Finalmente armé una clase de ayudante para hacer esto mucho más expresivo y menos desordenado. Aquí está un ejemplo de un posible resultado final:

mockPeopleRepository 
    .Setup(x => x.Find(ThatHas.AnExpressionFor<Person>() 
    .ThatMatches(correctPerson) 
    .And().ThatDoesNotMatch(deletedPerson) 
    .Build())) 
    .Returns(_expectedListOfPeople); 

Aquí está el artículo de blog que habla de él y le da al código fuente: http://awkwardcoder.com/2013/04/24/constraining-mocks-with-expression-arguments/

+0

Muy útil, gran contribución. – Paul

4

he encontrado que It.Is<T> se debe utilizar en lugar de It.IsAny<T> para obtener más resultados precisos

Page expectedPage = new Page {Id = 12, Title = "Some Title"}; 
_mockRepos.Setup(x => x.Single<Page>(It.Is<Expression<Func<Page, bool>>>(u => u.Compile().Invoke(expectedPage)))) 
         .Returns(() => expectedPage); 
Cuestiones relacionadas