Moq.Mock - jak ustawić metodę, która przyjmuje wyrażenie
Szydzę z interfejsu repozytorium i nie jestem pewien, jak skonfigurować metodę, która pobiera wyrażenie i zwraca obiekt? Używam Moq i NUnit
Interfejs:
public interface IReadOnlyRepository : IDisposable
{
IQueryable<T> All<T>() where T : class;
T Single<T>(Expression<Func<T, bool>> expression) where T : class;
}
Test z IQueryable już setup, ale nie wiem jak ustawić 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);
}
4 answers
Możesz ustawić go tak:
_mockRepos.Setup(x => x.Single<Page>(It.IsAny<Expression<Func<Page, bool>>>()))//.Returns etc...;
Jednak napotykasz jedną z wad Moq. Chciałbyś umieścić tam rzeczywiste wyrażenie zamiast używać It.IsAny
, ale Moq NIE obsługuje ustawiania metod, które przyjmują wyrażenia z określonymi wyrażeniami (jest to trudna funkcja do zaimplementowania). Trudność wynika z konieczności ustalenia, czy dwa wyrażenia są równoważne.
Więc w teście możesz zdać dowolny Expression<Func<Page,bool>>
and it will pass back / align = "left" / Wartość testu jest trochę rozcieńczona.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-02 00:56:10
Mieć .Returns call zwraca wynik wyrażenia względem zmiennej allPages.
_mockRepos.Setup(x => x.Single<Page>(It.IsAny<Expression<Func<Page, bool>>>()))
.Returns( (Expression<Func<Page, bool>> predicate) => allPages.Where(predicate) );
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-27 15:25:16
Stwierdziłem, że It.Is<T>
powinien być stosowany zamiast It.IsAny<T>
dla dokładniejszych wyników.
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);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-01 17:46:35
Użycie MOQ ' s It.IsAny<>
Bez .CallBack
zmusza cię do napisania kodu, który nie jest objęty Twoim testem. Zamiast tego pozwala na przechodzenie dowolnych zapytań/wyrażeń, czyniąc makietę praktycznie bezużyteczną z perspektywy testów jednostkowych.
Rozwiązanie: albo musisz użyć funkcji zwrotnej, aby przetestować wyrażenie, albo musisz lepiej ograniczyć swój mock. Tak czy inaczej jest bałagan i trudne. Zajmowałem się tym problemem tak długo, jak ćwiczyłem TDD. W końcu rzuciłem pomocnikiem Klasa, aby było to o wiele bardziej wyraziste i mniej bałaganiarskie. Oto przykład jednego możliwego wyniku końcowego:
mockPeopleRepository
.Setup(x => x.Find(ThatHas.AnExpressionFor<Person>()
.ThatMatches(correctPerson)
.And().ThatDoesNotMatch(deletedPerson)
.Build()))
.Returns(_expectedListOfPeople);
Oto artykuł na blogu, który mówi o tym i podaje kod źródłowy: http://awkwardcoder.com/2013/04/24/constraining-mocks-with-expression-arguments/
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-24 21:20:13