Тест удваивается (mocks / stubs) против цепочки методов или свободного синтаксиса интерфейса - PullRequest
2 голосов
/ 03 сентября 2010

У меня есть тестируемый код, который в основном выглядит следующим образом (конкретный код не важен для вопроса. Он здесь только для пояснительных целей):

public ICollection<Product> GetByCategory(string category, ISession session)
{
    return session
        .CreateCriteria(typeof(Product))
        .Add(Restrictions.Eq("Category", category))
        .List<Product>();
}

При этом используется цепочка методов (и решение, которое я ищу, также применимо к свободному синтаксису интерфейса ).

Я не заинтересован в поиске решений только для этого конкретного примера, я заинтересован в решении более общей проблемы. В этом примере я хотел бы только добавить ожидание для CreateCriteria. Однако, если я это сделаю, я получу исключение NullReferenceException, даже если у меня CreateCriteria возвращает заглушку, потому что метод Add возвращает ноль.

Мне бы хотелось, чтобы мой тест продолжал работать, даже если дополнительные методы связаны или метод Add удален.

Есть ли общая хитрость для уменьшения числа удвоенных / ожидаемых вызовов теста до тех, против которых я хочу утверждать, при использовании цепочки методов?

Решение, которое я могу придумать, состоит в создании шаблона T4, который перечисляет все методы типа и создает заглушку с ожиданиями, которые дают разные возвращаемые значения по умолчанию. Но мне интересно, есть ли более простые варианты.

Я использую Rhino.Mocks, но общее решение было бы еще более ценным.

Ответы [ 2 ]

1 голос
/ 10 августа 2011

Мне нужно что-то подобное для интерфейса NHibernate IQuery.Я использовал Castle.DymanicProxy и Rhino.Mocks со следующей реализацией Fake IRepository ...

internal class FakeRepository<TTypeOfModel> : IRepository<TTypeOfModel>
{
    ....

    public IQuery GetNamedQuery(string queryName)
    {
        return MockFactory.MockWithMethodChainingFor<IQuery>();
    }

    ....
}

internal static class MockFactory
{
    public static T MockWithMethodChainingFor<T>()
        where T : class
    {
        var generator = new ProxyGenerator();

        return generator.CreateInterfaceProxyWithTargetInterface(
            MockRepository.GenerateMock<T>(),
            new MethodChainingMockInterceptor<T>());
    }
}

internal class MethodChainingMockInterceptor<T> : StandardInterceptor
{
    protected override void PerformProceed(IInvocation invocation)
    {
        if ((Type)invocation.Method.ReturnType == typeof(T))
        {
            invocation.ReturnValue = invocation.Proxy;
        }
        else
        {
            base.PerformProceed(invocation);
        }
    }
}
1 голос
/ 03 сентября 2010

Возможный подход - заключить фиктивный объект в DynamicProxy, который всегда возвращает this для методов, которые являются частью свободного API и не имеют зарегистрированных ожиданий.Он делегирует обычному фиктивному объекту методы, для которых ожидания были записаны (или не являются частью свободного интерфейса).

Определение того, для каких методов определены ожидания, будет, конечно, сильно зависеть от MockLibrary.Не беглые методы могут быть легко проверены на использование интроспекции.

Может быть, одна из библиотек уже встроила это?

...