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);
}
Author: jfar, 2010-05-02

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.

 37
Author: Jason Punyon,
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) );
 6
Author: wllmsaccnt,
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);
 4
Author: Paul,
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/

 1
Author: Byron Sommardahl,
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