c# - unit - Moq.Mock<T>-cómo configurar un método que toma una expresión
verify moq (4)
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) );
Me 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 NUnit
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 ya configurado, pero no sé cómo configurar el T Single:
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);
}
He encontrado que It.Is<T>
debe usar en lugar de It.IsAny<T>
para obtener resultados más 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);
Puede configurarlo de esta manera:
_mockRepos.Setup(x => x.Single<Page>(It.IsAny<Expression<Func<Page, bool>>>()))//.Returns etc...;
Sin embargo, te enfrentas a una de las deficiencias de Moq. En lugar de usar It.IsAny
, It.IsAny
poner una expresión real, 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.
Entonces, en su prueba puede pasar cualquier Expression<Func<Page,bool>>
y devolverá lo que haya configurado el simulacro para regresar. El valor de la prueba está un poco diluido.
Usar It.IsAny<>
Moq sin .CallBack
te obliga a escribir código que no está cubierto por tu prueba. 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 usar una Devolución de llamada para probar la expresión O necesita restringir su simulación 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í hay 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 del blog que habla al respecto y proporciona el código fuente: http://awkwardcoder.com/2013/04/24/constraining-mocks-with-expression-arguments/