модульное тестирование заводского метода - PullRequest
5 голосов
/ 07 марта 2012

предположим, у меня есть несколько OrderProcessor с, каждый из которых обрабатывает заказ немного по-своему.
Решение о том, какой OrderProcessor использовать, принимается в соответствии со свойствами объекта Order и выполняетсяс помощью заводского метода, например, так:

public IOrderProcessor CreateOrderProcessor(IOrdersRepository repository, Order order, DiscountPercentages discountPercentages)
{
    if (order.Amount > 5 && order.Unit.Price < 8)
    {
        return new DiscountOrderProcessor(repository, order, discountPercentages.FullDiscountPercentage);
    }

    if (order.Amount < 5)
    {
        // Offer a more modest discount
        return new DiscountOrderProcessor(repository, order, discountPercentages.ModestDiscountPercentage);
    }

    return new OutrageousPriceOrderProcessor(repository, order);
}

Теперь моя проблема в том, что я хочу убедиться, что возвращенный OrderProcessor получил правильные параметры (например, правильный процент скидки).
Однако эти свойства не являются общедоступными для OrderProcessor объектов.

Как бы вы предложили мне справиться с этим сценарием?

Единственное решение, которое мне удалось придумать, - сделать свойство процента скидок для OrderProcessor открытым, но это кажется излишним, делать это только для модульного тестирования ...

Ответы [ 3 ]

3 голосов
/ 07 марта 2012

Одним из способов решения этой проблемы является изменение полей, которые вы хотите проверить, на внутренние, а не на частные, а затем установка внутренних элементов проекта, видимых для проекта тестирования. Вы можете прочитать об этом здесь: http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx

Вы бы сделали что-то подобное в вашем файле AssemblyInfo.cs:

[assembly:InternalsVisibleTo("Orders.Tests")]

Хотя вы можете утверждать, что ваши юнит-тесты не обязательно должны заботиться о личных полях вашего класса. Может быть, лучше передать значения фабричному методу и написать модульные тесты для ожидаемого результата, когда на интерфейсе вызывается какой-то метод (при условии, что Calculate () или что-то подобное).

Или другой подход заключается в модульном тестировании конкретных типов (DiscountOrderProcessor и т. Д.) И подтверждении их возвращаемых значений из открытых методов / свойств. Затем напишите модульные тесты для фабричного метода, чтобы он правильно возвращал правильный тип реализации интерфейса.

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

1 голос
/ 07 марта 2012

Если процент скидки не является публичным, то он не является частью договора IOrderProcessor и, следовательно, не нуждается в проверке. Просто получите набор модульных тестов для DiscountOrderProcessor, чтобы убедиться, что он правильно вычисляет ваши скидки на основе процента скидки, переданного через конструктор.

0 голосов
/ 07 марта 2012

У меня есть пара вариантов, как я это вижу.Вы можете создать специализации DiscountOrderProcessor:

public class FullDiscountOrderProcessor : DiscountOrderProcessor
{
    public FullDiscountOrderProcessor(IOrdersRepository repository, Order order):base(repository,order,discountPercentages.FullDiscountPercentage)
    {}
}

public class ModestDiscountOrderProcessor : DiscountOrderProcessor
{
    public ModestDiscountOrderProcessor (IOrdersRepository repository, Order order):base(repository,order,discountPercentages.ModestDiscountPercentage)
    {}
}

и проверить, верен ли верный тип.

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

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

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

Вам нужно как-то проверить фактические значения, которые оставляют вас с:

вы можете сделать свойства общедоступными (или внутренними - используя InternalsVisibleTo), чтобы вы могли их опросить.

вы можете взять возвращенный объект и проверить, правильно ли он применяет скидку к некоторому объекту, который вы передаете ему.

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

...