юниттест отражения .Net
От: Aggtaa Россия  
Дата: 14.03.11 11:12
Оценка:
Только осваиваю юниттестирование. Возникает множество вопросов, например:

Как протестировать следующий код? Создавать мокап домена приложений?
    public class ActionProviders
    {
        private static readonly Dictionary<string, IActionProvider> _providers = new Dictionary<string, IActionProvider>(StringComparer.InvariantCultureIgnoreCase);

        static ActionProviders()
        {
            Load();
        }

        public static void Load()
        {
            //TODO TEST MISSING -- how to test it???
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                foreach (Type type in assembly.GetTypes())
                    try
                    {
                        if (type.GetInterface(typeof(IActionProvider).FullName) != null)
                        {
                            if (type.GetConstructor(new Type[0]) != null)
                                _providers.Add(type.Name.Replace("Provider", ""), (IActionProvider)Activator.CreateInstance(type));
                        }
                    }
                    catch (TargetInvocationException) { }
                    catch (TypeInitializationException) { }
                    catch (ReflectionTypeLoadException) { }
                    catch (ArgumentNullException) { }
                    catch (ArgumentException) { }
            }
        }

        public static IDictionary<string, IActionProvider> Providers
        {
            get { return _providers; }
        }
    }
A.
Re: юниттест отражения .Net
От: ulu http://sm-art.biz
Дата: 14.03.11 11:18
Оценка:
Все очень просто -- надо создать в тестовой сборке класс, имплементирующий IActionProvider, и затем проверить, правильно ли все происходит.

Вы писали:

A>Только осваиваю юниттестирование. Возникает множество вопросов, например:


A>Как протестировать следующий код? Создавать мокап домена приложений?

A>
A>    public class ActionProviders
A>    {
A>        private static readonly Dictionary<string, IActionProvider> _providers = new Dictionary<string, IActionProvider>(StringComparer.InvariantCultureIgnoreCase);

A>        static ActionProviders()
A>        {
A>            Load();
A>        }

A>        public static void Load()
A>        {
A>            //TODO TEST MISSING -- how to test it???
A>            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
A>            {
A>                foreach (Type type in assembly.GetTypes())
A>                    try
A>                    {
A>                        if (type.GetInterface(typeof(IActionProvider).FullName) != null)
A>                        {
A>                            if (type.GetConstructor(new Type[0]) != null)
A>                                _providers.Add(type.Name.Replace("Provider", ""), (IActionProvider)Activator.CreateInstance(type));
A>                        }
A>                    }
A>                    catch (TargetInvocationException) { }
A>                    catch (TypeInitializationException) { }
A>                    catch (ReflectionTypeLoadException) { }
A>                    catch (ArgumentNullException) { }
A>                    catch (ArgumentException) { }
A>            }
A>        }

A>        public static IDictionary<string, IActionProvider> Providers
A>        {
A>            get { return _providers; }
A>        }
A>    }
A>
Re[2]: юниттест отражения .Net
От: Aggtaa Россия  
Дата: 14.03.11 11:32
Оценка:
Здравствуйте, ulu, Вы писали:

ulu>Все очень просто -- надо создать в тестовой сборке класс, имплементирующий IActionProvider, и затем проверить, правильно ли все происходит.

"Все происходит" — это что? Я не хочу проверять реализаторов IActionProvider — для этого есть отдельные тесты. Мне бы убедиться, что все нужные типы загружаются и не загружаются лишние. Т.е. логику именно метода Load.

Можете код теста привести в пример?

И еще возник вопрос. Как быть, если само существование тестов уже влияет на поведение тестируемого кода?
A.
Re[3]: юниттест отражения .Net
От: Lloyd Россия  
Дата: 14.03.11 11:41
Оценка: +1
Здравствуйте, Aggtaa, Вы писали:

ulu>>Все очень просто -- надо создать в тестовой сборке класс, имплементирующий IActionProvider, и затем проверить, правильно ли все происходит.

A>"Все происходит" — это что? Я не хочу проверять реализаторов IActionProvider — для этого есть отдельные тесты. Мне бы убедиться, что все нужные типы загружаются и не загружаются лишние. Т.е. логику именно метода Load.

Вы сами выделили отдельный элемент функциональности, который вы хотите оттестировать — фильтрацию типов. Вот это и вынесите в отдельный метод и оттестируйте его. Сигнатура: IEnumerable<Type> -> IEnumerable<Type>.

A>Можете код теста привести в пример?


A>И еще возник вопрос. Как быть, если само существование тестов уже влияет на поведение тестируемого кода?


Просто вынесите код тестов в отдельную сборку.
Re[3]: юниттест отражения .Net
От: ulu http://sm-art.biz
Дата: 14.03.11 11:51
Оценка:
Вы тестируете именно метод Load. Вызываете его, а потом проверяете, добавился в Providers ли экземпляр того класса, который Вы создали для проверки.

А Вы MEF не пробовали здесь применить?

Вы писали:

A>Здравствуйте, ulu, Вы писали:


ulu>>Все очень просто -- надо создать в тестовой сборке класс, имплементирующий IActionProvider, и затем проверить, правильно ли все происходит.

A>"Все происходит" — это что? Я не хочу проверять реализаторов IActionProvider — для этого есть отдельные тесты. Мне бы убедиться, что все нужные типы загружаются и не загружаются лишние. Т.е. логику именно метода Load.

A>Можете код теста привести в пример?


A>И еще возник вопрос. Как быть, если само существование тестов уже влияет на поведение тестируемого кода?
Re[4]: юниттест отражения .Net
От: Aggtaa Россия  
Дата: 14.03.11 11:56
Оценка:
Здравствуйте, Lloyd, Вы писали:

A>>"Все происходит" — это что? Я не хочу проверять реализаторов IActionProvider — для этого есть отдельные тесты. Мне бы убедиться, что все нужные типы загружаются и не загружаются лишние. Т.е. логику именно метода Load.

L>Вы сами выделили отдельный элемент функциональности, который вы хотите оттестировать — фильтрацию типов. Вот это и вынесите в отдельный метод и оттестируйте его. Сигнатура: IEnumerable<Type> -> IEnumerable<Type>.
Так?
        private static IEnumerable<Type> GetAssemblyProviderTypes(IEnumerable<Type> types)
        {
            foreach (Type type in types)
                if ((type.GetInterface(typeof(IActionProvider).FullName) != null)
                        && (type.GetConstructor(new Type[0]) != null))
                    yield return type;
        }
Для тестирования придется этот метод делать public или хотя бы internal. Вытаскивать с мясом наружу кусок логики неправильно, мне кажется. И ведь я хочу протестировать еще и загрузку. Типа "валидно написанные классы валидно загружаются, невалидно написанные и левые классы не загружаются".

Но это мелочи по сравнению с public логикой. Мне неинтересно тестировать маленький аспект работы кода в отдельных 3 строчках.
Мне нужно убедиться, что вся публичная функциональность этого кода ведет себя предсказуемо, повторяемо и правильно. В этом же смысл юниттестирования?

A>>И еще возник вопрос. Как быть, если само существование тестов уже влияет на поведение тестируемого кода?

L>Просто вынесите код тестов в отдельную сборку.
Сборка с тестами все равно будет загружена в домен на момент выполнения теста.
A.
Re[4]: юниттест отражения .Net
От: Aggtaa Россия  
Дата: 14.03.11 12:08
Оценка:
Здравствуйте, ulu, Вы писали:

A>>"Все происходит" — это что? Я не хочу проверять реализаторов IActionProvider — для этого есть отдельные тесты. Мне бы убедиться, что все нужные типы загружаются и не загружаются лишние. Т.е. логику именно метода Load.

ulu>Вы тестируете именно метод Load. Вызываете его, а потом проверяете, добавился в Providers ли экземпляр того класса, который Вы создали для проверки.
Как быть с "не загружаются лишние"?

ulu>А Вы MEF не пробовали здесь применить?

Не пробовал, потому что .Net 2.0.
A.
Re[5]: юниттест отражения .Net
От: Lloyd Россия  
Дата: 14.03.11 12:15
Оценка: 4 (1)
Здравствуйте, Aggtaa, Вы писали:

L>>Вы сами выделили отдельный элемент функциональности, который вы хотите оттестировать — фильтрацию типов. Вот это и вынесите в отдельный метод и оттестируйте его. Сигнатура: IEnumerable<Type> -> IEnumerable<Type>.

A>Так?
A>
A>        private static IEnumerable<Type> GetAssemblyProviderTypes(IEnumerable<Type> types)
A>        {
A>            foreach (Type type in types)
A>                if ((type.GetInterface(typeof(IActionProvider).FullName) != null)
A>                        && (type.GetConstructor(new Type[0]) != null))
A>                    yield return type;
A>        }
A>


Или
return types.Where(IsValidType);


A>Для тестирования придется этот метод делать public или хотя бы internal. Вытаскивать с мясом наружу кусок логики неправильно, мне кажется. И ведь я хочу протестировать еще и загрузку. Типа "валидно написанные классы валидно загружаются, невалидно написанные и левые классы не загружаются".


Ну, как не крути, а необходимость тестировать все-таки вынуждает иначе подходить к проектированию. От этого не уйти.

A>Но это мелочи по сравнению с public логикой. Мне неинтересно тестировать маленький аспект работы кода в отдельных 3 строчках.

A>Мне нужно убедиться, что вся публичная функциональность этого кода ведет себя предсказуемо, повторяемо и правильно. В этом же смысл юниттестирования?

Это нормально. SRP.

A>>>И еще возник вопрос. Как быть, если само существование тестов уже влияет на поведение тестируемого кода?

L>>Просто вынесите код тестов в отдельную сборку.
A>Сборка с тестами все равно будет загружена в домен на момент выполнения теста.

Ну так только на момент выполнения теста.
Re[5]: юниттест отражения .Net
От: ulu http://sm-art.biz
Дата: 14.03.11 18:49
Оценка: -1
Здравствуйте, Aggtaa, Вы писали:

A>Здравствуйте, ulu, Вы писали:


A>>>"Все происходит" — это что? Я не хочу проверять реализаторов IActionProvider — для этого есть отдельные тесты. Мне бы убедиться, что все нужные типы загружаются и не загружаются лишние. Т.е. логику именно метода Load.

ulu>>Вы тестируете именно метод Load. Вызываете его, а потом проверяете, добавился в Providers ли экземпляр того класса, который Вы создали для проверки.
A>Как быть с "не загружаются лишние"?

Ну, например, создать еще один класс, который *не* реализует IActionProvider, и проверить, что он не загружается.
Re[5]: юниттест отражения .Net
От: -VaS- Россия vaskir.blogspot.com
Дата: 19.03.11 19:10
Оценка: -1
A>Для тестирования придется этот метод делать public или хотя бы internal. Вытаскивать с мясом наружу кусок логики неправильно, мне кажется. И ведь я хочу протестировать еще и загрузку. Типа "валидно написанные классы валидно загружаются, невалидно написанные и левые классы не загружаются".

Как уже было сказано, у тебя нарушается SRP: 1. Загрузка 2. Фильтрация. Поэтому п. 2 выделяем в отдельную роль (интерфейс) — AssemblyProviderFilter с твоим методом GetAssemblyProviderTypes(), который с удовольствием передаем в метод Load() (раз уж у тебя зачем-то статический класс, а то бы — в конструктор). А его реализацию элементарно тестируем отдельно.

A>Но это мелочи по сравнению с public логикой. Мне неинтересно тестировать маленький аспект работы кода в отдельных 3 строчках.

A>Мне нужно убедиться, что вся публичная функциональность этого кода ведет себя предсказуемо, повторяемо и правильно. В этом же смысл юниттестирования?

Нет, смысл юнит-тестирования в тестировании отдельных аспектов поведения (по одному на тест) единичного класса. А то, что ты хочешь сделать — это интеграционный тест (как небольшая совокупность классов взаимодействует между собой и с внешним, неконтролируемым миром). Такие тесты нужны, но их, во-первых, мало, а во-вторых они не стремятся покрыть весь функционал, они что-то вроде smoke-тестов. Их мало, потому что создавать и поддерживать их сложно, а диагностируемость оставляет желать много лучшего.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.