2016-06-24 2 views
3

Я пытаюсь проверить следующий код:Является ли это плохой настройкой Moq или недостатком Moq?

public async Task<Activity> Get(long ID, Recruiter User, bool IsArchived = false) 
{ 
    Activity result = await collection.FirstOrDefault(x => x.ID == ID && x.Recruiter.CompanyID == User.CompanyID && (!x.Archived || IsArchived)); 
    return result; 
} 

С следующего теста:

[TestMethod] 
public async Task GetDoesThings() 
{ 
    long ID = 1; 
    bool IsArchived = false; 
    Recruiter User = new Recruiter() 
    { 
     CompanyID = 1 
    }; 

    ActivitiesMock.Setup(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived))).ReturnsAsync(new Activity()); 

    Activity result = await repo.Get(ID, User); 

    ActivitiesMock.Verify(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived))); 
} 

(я знаю, что есть разные способы писать, это самая последняя итерация мы в пробы.)

ActivitiesMock относится к collection, найденному по адресу Get(long ID, Recruiter User, bool IsArchived = false). Недавно мы писали обертки для того, чтобы попробовать и испытать наш Entity более эффективен вызовами, но мы бежим в эту ошибку при попытке проверить звонки сделаны правильно:

Метод испытания ExampleProject.Tests.Backend.Repositories. ActivityRepositoryTests.GetDoesThings выбрасывает исключение: Moq.MockException: Ожидаемое обращение к макету хотя бы один раз, но никогда не выполнялось: x => x.FirstOrDefault (y => (y.ID == .ID & & y.Recruiter. CompanyID == .User.CompanyID) & & (! (Y.Archived) || .IsArchived))

Конфигурированная установка s: x => x.FirstOrDefault (y => (y.ID == .ID & & y.Recruiter.CompanyID == .User.CompanyID) & & (! (y.Archived) || .IsArchived)), Times.Never

Выполненные вызовы: IAppCollection`2.FirstOrDefault (х => (((x.ID == значение (ExampleProject.Backend.Repositories.ActivityRepository + <> c__DisplayClass2_0) .id) AndAlso (x.Recruiter.CompanyID == value (ExampleProject.Backend.Repositories.ActivityRepository + <> c__DisplayClass2_0) .User.CompanyID)) AndAlso (Not (x.Archived) Значение OrElse (ExampleProject.Backend.Repositories.ActivityRepository + <> c__DisplayClass2_0). IsArchived)))

В этом случае обертка (collection) является макетом интерфейса. Цель состоит в том, чтобы гарантировать, что репозиторий вызывает правильное выражение на оболочке, так что мы знаем, что предикат, который передается в Entity DbSet, верен, не беспокоясь обо всех беспорядочных абсурдах async.

Ложная Setup() с полным предиката не появляется можно найти, когда тест побежал, и когда я изменить Setup() к It.IsAny<Expression<Func<Activity, bool>>>() он работает макет и обеспечивает возвращение, но Verify вызов не работает. Так, бег:

ActivitiesMock.Setup(x => x.FirstOrDefault(It.IsAny<Expression<Func<Activity, bool>>>())).ReturnsAsync(new Activity()); 

Activity result = await repo.Get(ID, User); 

Assert.IsNotNull(result); 
ActivitiesMock.Verify(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived))); 

Передает Assert, но терпит неудачу Проверьте, в то время как работает:

ActivitiesMock 
    .Setup(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived))) 
    .ReturnsAsync(new Activity()) 
    .Verifiable(); 

Activity result = await repo.Get(ID, User); 

Assert.IsNotNull(result); 
ActivitiesMock.Verify(); 

Сбой на утверждают.

Похоже, что он терпит неудачу, потому что он ожидает того же типа объектов. Я пытаюсь сделать то, что Moq не может обработать, или я пропущу что-то, что мне нужно сделать, чтобы проверить правильность проверки?

По желанию, конкретная реализация обертки LINQ-к-ENTITY (collection) является:

public Task<T> FirstOrDefault(Expression<Func<T, bool>> Predicate) 
{ 
    return DbSet.FirstOrDefaultAsync(Predicate); 
} 

Хотя сама обертка не используется, но интерфейс для него является осмеиваемым, и это то, что мы тестируем.

+0

Является ли этот вызов 'FirstOrDefault' обычным методом LINQ? Если это так, вы не можете издеваться над ним с помощью Moq, потому что это метод расширения. –

+0

Это не так. Это оболочка вокруг метода LINQ to-Entities. – Codeacula

+0

Вы подтверждаете, что вызывается метод LINQ 'FirstOrDefault' по умолчанию, которого нет. Можете ли вы разместить свою обертку, пожалуйста? –

ответ

1

Ответ не является ни тем, ни другим. Поскольку анонимные функции должны создавать экземпляры классов для хранения предоставленных данных, они создают DisplayClass экземпляры для хранения данных. Поскольку эти экземпляры создаются в разных пространствах имен (между прочим), они не проходят, когда Moq называет .Equals против них.

Мы решили эту проблему, написав наши тесты, как например:

ActivitiesMock 
    .Setup(x => x.Where(It.IsAny<Expression<Func<Activity, bool>>>())) 
    .Returns((Expression<Func<Activity, bool>> x) => 
    { 
     actualPredicate = x; 
     return queryMock.Object; 
    }); 

После создания действительной и недействительной деятельности по предоставлению предиката, чтобы убедиться, что он возвращает true или false правильно:

Assert.IsTrue(actualPredicate.Compile().Invoke(validActivity)); 

Предоставленным пока это немного взломанно, но на первый взгляд это не кажется слишком большим, как решение для пожарных контейнеров, и это способ обеспечить, чтобы предоставляемые звонки выполняли то, что мы ожидаем от них, чего мы хотим.

Обновление (7 сентября 2016 года): До сих пор это работало хорошо для нас. Мы столкнулись с проблемой, в которой операторы LINQ-to-Entity не работают должным образом, потому что LINQ чувствителен к регистру, а SQL-генерация не является, но поскольку это не является нарушителем для нас, мы просто хорошо.

+0

Если кто-то придумал ответ, который позволяет легко тестировать лямбда-выражения без необходимости значительно менять тесты, я буду рад задать новый вопрос/отметьте его правильно. – Codeacula

Смежные вопросы