Как выполнить модульный тестовый метод, который использует статические классы, без родинок или изоляторов? - PullRequest
1 голос
/ 31 января 2012

У меня есть метод

     public int GetHighestPriorityPriceRecordIndex(SearchAndExtractReply_2 priceInfoReply)
    {
        int index = 0;

        var priceExposableColumn = GetPriceColumn(priceInfoReply, "LPCIsPriceExposable");

        var pricingSourceIDColumn = GetPriceColumn(priceInfoReply, "LPCPricingSourceID");

        var priceExposablePriority = new Dictionary<string, int> { { "Y", 2 }, { "N", 1 } };

        var pricingSourcePriority = new Dictionary<string, int> { { "USA", 5 }, { "EME", 4 }, { "ASI", 3 }, { "DER", 2 }, { "NUS", 1 } };

        if (priceExposableColumn.Value != null)
            for (int i = 1; i < priceExposableColumn.Value.Length; i++)
                if (priceExposablePriority[priceExposableColumn.Value[i]] > priceExposablePriority[priceExposableColumn.Value[index]]
                    && pricingSourcePriority[pricingSourceIDColumn.Value[i]] > pricingSourcePriority[pricingSourceIDColumn.Value[index]])
                    index = i;

        return index;
    }

    private static StringColumn GetPriceColumn(SearchAndExtractReply_2 priceInfoReply, string columnName)
    {
        return (StringColumn)SearchAndExtractReply_2_Extension.GetColumn(priceInfoReply, columnName);
    }

Я хочу провести модульное тестирование класса, в котором есть этот метод, этот метод использует статические классы и метод SearchAndExtractReply_2_Extension.GetColumn. Как лучше реорганизовать этот код так, чтобы я мог протестировать этот метод без Moles или Isolator? Или лучше использовать родинки, чтобы изолировать код? Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 31 января 2012

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

И об этом рефакторинге. Введите новый класс, единственной обязанностью которого будет извлечение столбца из объекта SearchAndExtractReply_2. Все довольно просто:

public interface IColumnExtractor
{
    StringColumn GetPriceColumn(SearchAndExtractReply_2 source,
        string columnName);
}

public class ColumnExtractor : IColumnExtractor
{
    public StringColumn GetPriceColumn(SearchAndExtractReply_2 source, 
        string columnName)
    {
        return (StringColumn)SearchAndExtractReply_2_Extension.GetColumn(source, 
            columnName);
    }
}

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

public int GetHighestPriorityPriceRecordIndex(
    SearchAndExtractReply_2 priceInfoReply, IColumnExtractor columnExtractor)
{
    // use extractor object instead of static method
}

Тогда вы можете использовать любой бесплатный фреймворк (например, FakeItEasy или Moq ).

2 голосов
/ 31 января 2012

Если вы зависите от чего-то, оно должно быть передано методу. Тогда ваш API понятен, и вы можете сказать извне, что нужно, а что можно высмеивать. Это означает, что вы разделяете логику построения и бизнес-логику. В сочетании с инфраструктурой внедрения зависимостей, такой как Unity или Castle, она даст вам хороший тестируемый код в ваших модульных тестах и ​​код, который легко использовать в производстве.

Я бы создал интерфейс для вашего SearchAndExtractReply_2_Extension, а затем передал бы его в качестве параметра на GetHighestPriorityPriceRecordIndex (или, возможно, на конструктор, если он используется в нескольких местах). Затем вы можете смоделировать всю зависимость или передать в нее «реальную реализацию» при проведении интеграционного тестирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...