Методы moq'ING, где выражение> передается в качестве параметров


Я очень новичок в модульном тестировании и издевательствах! Я пытаюсь написать некоторые модульные тесты, которые охватывают некоторый код, который взаимодействует с хранилищем данных. Доступ к данным инкапсулируется IRepository:

interface IRepository<T> {
    ....
    IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate);
    ....
}

код, который я пытаюсь проверить, используя конкретную реализацию ioc'D IRepository выглядит так:

public class SignupLogic {
    private Repository<Company> repo = new Repository<Company>();

    public void AddNewCompany(Company toAdd) {
        Company existingCompany = this.repo.FindBy(c => c.Name == toAdd.Name).FirstOrDefault();

        if(existingCompany != null) {
            throw new ArgumentException("Company already exists");
        }

        repo.Add(Company);
        repo.Save();
    }
}

так что я проверяю логику SignupLogic.AddNewCompany() сам, а не логика и конкретный репозиторий, я издеваюсь над IRepository и передавая его в SignupLogic. Издевательский репозиторий выглядит так:

Mock<Repository> repoMock = new Mock<Repository>();
repoMock.Setup(moq => moq.FindBy(c => c.Name == "Company Inc")....

который возвращает в памяти IEnumberable содержащий объект компании с именем, установленным в "Company Inc". Модульный тест, который вызывает SignupLogic.AddNewCompany создает компанию с повторяющимися деталями и пытается передать это, и я утверждаю, что ArgumentException создается с сообщением "компания уже существует". Этот тест не проходит.

отладка через модульный тест и AddNewCompany () при его запуске будет казаться, что existingCompany всегда имеет значение null. В отчаянии я обнаружил, что если я обновлю SignupLogic.AddNewCompany () так что вызов FindBy выглядит так:

Company existingCompany = this.repo.FindBy(c => c.Name == "Company Inc").FirstOrDefault();

тест проходит, что говорит мне о том, что Moq отвечает только на код, который ровно то же самое, что я установил в своем тестовом приборе. Очевидно, что это не особенно полезно при тестировании, что любая дублирующая компания отклоняется Сигнуплогика.AddNewCompany.

Я пробовал настроить moq.FindBy(...) использовать " есть.ItAny", но это тоже не заставляет тест проходить.

из всего, что я читаю, кажется, что тестирование выражений, как я пытаюсь, на самом деле не работает с Moq здесь. Возможно ли это? Пожалуйста, помогите!

3   51   2011-03-04 19:42:04

3 ответа:

вероятно, правильно, что только Expression С точно такой же структурой (и буквальных значений) будут совпадать. Я предлагаю вам использовать перегрузку Returns() что позволяет использовать параметры макет вызывается с:

repoMock.Setup(moq => moq.FindBy(It.IsAny<Expression<Func<Company, bool>>>())
        .Returns((Expression<Func<Company, bool>> predicate) => ...);

на ..., вы можете использовать predicate чтобы вернуть соответствующие компании (и, возможно, даже бросить исключение, если соответствующие компании не то, что вы ожидали). Не очень красиво, но я думаю, что это сработает.

вы должны быть в состоянии использовать It.IsAny<>() чтобы выполнить то, что вы хотите сделать. С использованием It.IsAny<>() вы можете просто настроить тип возврата для вашей установки, чтобы проверить каждую ветвь вашего кода.

It.IsAny<Expression<Func<Company, bool>>>()

первый тест, возвращает компанию независимо от предиката, который вызовет исключение бросить:

var repoMock = new Mock<IRepository<Company>>();
repoMock.Setup(moq => moq.FindBy(It.IsAny<Expression<Func<Company, bool>>>())).Returns(new List<Company>{new Company{Name = "Company Inc"}});
var signupLogic = new SignupLogic(repoMock.Object);
signupLogic.AddNewCompany(new Company {Name = "Company Inc"});
//Assert the exception was thrown.

второй тест, сделать тип возврата пустой список ведьма вызовет add для вызова.:

var repoMock = new Mock<IRepository<Company>>();
repoMock.Setup(moq => moq.FindBy(It.IsAny<Expression<Func<Company, bool>>>())).Returns(new List<Company>());
var signupLogic = new SignupLogic(repoMock.Object);
signupLogic.AddNewCompany(new Company {Name = "Company Inc"});
repoMock.Verify(r => r.Add(It.IsAny<Company>()), Times.Once());

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

в рамках Moq. Важно поставить .Returns() для функций в противном случае он не соответствует. Так что если вы этого не сделали, это ваша проблема.

repoMock.Setup(moq => moq.FindBy(c => c.Name == "Company Inc").Returns(....