Можно, но если работаешь с какой-то известной библиотекой, то по деталям ошибки сразу можно определить ее причину.
Примечание: как оказалось, код показанный выше далеко не всегда даст английскую локализацию. Чаще всего строка информации формируется во время исключения, а не при первом обращении к Message (можно посмотреть в Reflector).
Смотря как реализована зависимость. Если это C++/CLI сборка, то Assembly.Load должен сработать.
Если это native dll, то тут нужно гуглить такую же статью на С++. В SysInternals инструментах это реализовано, так что должен быть соответствующий WinAPI вызов. Может у Рихтера в книге даже реализация найдется. В любом случае нужно будет перехватывать PInvoke вызовы к unmanaged DLL. Либо PInvoke обертки выделять в отдельные сборки и анализировать в AssemblyResolve, либо пробовать приспособить TypeResolve, либо принять соглашение об именовании таких оберток и использовать аспектное программирование.
М… Фактически тесты генерируются по спецификациям. Вручную нужно написать:
— спецификации.
— get акксессор, если для свойства он еще не определен.
— дескриптор свойства, если для данного типа свойств он еще не определен.
У меня в последнем проекте такая статистика:
— 56 спецификаций, в которых в сумме проверяется 216 свойств
— 21 аксессор
— 3 пользовательских дескриптора
Фактически тестом можно считать одно проверяемое свойство в спецификации. Тест генерируется из ожидаемых данных спецификации, действительных данных из аксессора и логики сопоставления из дескриптора.
Не знаю как сделано в Code Contract, но в Design By Contract проверка выглядит примерно так (проверки в статическом классе Check):
public double GetParameter( Vector point )
{
Check.Require( !Direction.IsZeroLength, "Направление линии не должно быть вырожденным" );
// Проверка на то что параметр t существует и корректен
Check.Ensure( t.Count > 0, "Если точка лежит на линии, то у нее должен быть определен параметр" );
Check.Ensure( Op.Eq( t.Max( ), t.Min( ) ), "Разброс значений параметра t не должен быть больше заданной точности" );
// Возвращаем среднее значение
return t.Average( );
}
Своей цели обезопасить программу от неверных данных он служит. Мне Design By Contract в таком виде нравится.
В общем, если под Code Contract подразумевается явное указание того, какие данные требуются на входе и выходе метода, то это не интеграционное тестирование. У меня такие проверки есть — класс Utils.Common.Check. Эти проверки не предназначены для тестирования системы — это скорее защита программы от некорректных данных.
Один и тот же тест можно отнести в разные группы по разным срезам классификаций. Нагрузочное тестирование, как правило, происходит либо при системном тестировании, либо при интеграционном.
Я не претендую на новизну идеи. С Fitnesse не знаком и его возможностей не знаю. Но поглядев на их Wiki могу сказать, что движок Fitnesse очень отличен от моего:
1) Отношение к тестовым данным.
Насколько я понял, тестовые данные всегда задаются в табличном виде. Несколько аргументов и несколько проверяемых критериев. Но что делать в Fitnesse когда тестовые данные — это целый файл? Логично именно файл передавать как данные, если тестируется конвертирование документа в другой формат, к примеру.
У меня тестовые данные находятся либо в самой спецификации, либо в отдельном файле. В обоих случаях файлы хранятся в DLL тестового проекта как Embedded Resource. Это позволяет:
— Включать интеграционные тесты вместе со всеми данными в систему контроля версий.
— Всегда иметь под рукой спецификации и тестовые данные, когда работаешь в студии.
2) Считывание пользовательских типов данных.
Насколько просто в Fitnesse считать из спецификации данные такого вида?
Это коллекция точек в двумерном пространстве.
Мой движок заточен на расширяемость пользовательскими типами данных.
3) Ориентированность
Для тестирования в Fitness составляются таблицы. У меня же для каждого экземпляра тестовых данных пишется отдельная спецификация. Приблизительно это означает, что каждый ряд из таблицы Fitness разворачивается в спецификацию.
Это отличие продиктовано отношением к тестовым данным. У меня сложилось впечатление, что Fitnesse ориентирован на более низкоуровневое unit-тестирование. У меня же упор на интеграционное. Мне сложно объяснить без демонстрации кода. Скоро опубликую статью про мой движок, там покажу что я имею ввиду.
4) Чистота кода
Мой движок не требует объявлять место хранения для свойств в классе. Такого вида код не встречается (http://schuchert.wikispaces.com/FitNesse.Tutorials.1):
private int channel;
public void setChannel(int channel) {
this.channel = channel;
}
Такой код никому не интересен. Зачем писать служебный код? Он не решает задачу тестирования. В коде должны быть вычисления реальных значения свойств, а данные уже есть в спецификации.
5) Простой тестовый вывод
У меня простой движок, он не генерирует HTML отчеты. У него простой консольный вывод в котором указано все что требуется программисту для исправления ошибки. При тестировании из-под студии консольный вывод сохраняется в результатах прогона теста.
В том проекте инициализация свойств была довольно сложной. Не в плане вычислений, а в плане выставления зависимостей. Поэтому я специально вставлял null, чтобы если забуду инициализировать кинулось NullReferenceException.
А так да, в общем случае вызывать конструктор по умолчанию полезно.
Честно говоря я не знал про WindowsAPICodePack. Сейчас скачал его, посмотрел семплы. В чем отличия от Ookii:
— API.
— Некоторые диалоги реализованы только под WinForms
— Не нашел Credentials диалога
В Ookii два варианта диалогов — с зависимостью от WinForms библиотек или с зависимостью от WPF. Совместимость с предыдущими виндами нужно проверять на конкретных диалогах.
Примечание: как оказалось, код показанный выше далеко не всегда даст английскую локализацию. Чаще всего строка информации формируется во время исключения, а не при первом обращении к Message (можно посмотреть в Reflector).
private void CurrentDomain_UnhandledException( object sender, UnhandledExceptionEventArgs args )
{
var current = Thread.CurrentThread.CurrentUICulture;
Thread.CurrentThread.CurrentUICulture = new CultureInfo( "en-US" );
Logger.Error( args.ExceptionObject as Exception );
Thread.CurrentThread.CurrentUICulture = current;
}
Если это native dll, то тут нужно гуглить такую же статью на С++. В SysInternals инструментах это реализовано, так что должен быть соответствующий WinAPI вызов. Может у Рихтера в книге даже реализация найдется. В любом случае нужно будет перехватывать PInvoke вызовы к unmanaged DLL. Либо PInvoke обертки выделять в отдельные сборки и анализировать в AssemblyResolve, либо пробовать приспособить TypeResolve, либо принять соглашение об именовании таких оберток и использовать аспектное программирование.
То, что хранится в ресурсах, будет JIT компилится всегда, похоже.
— спецификации.
— get акксессор, если для свойства он еще не определен.
— дескриптор свойства, если для данного типа свойств он еще не определен.
У меня в последнем проекте такая статистика:
— 56 спецификаций, в которых в сумме проверяется 216 свойств
— 21 аксессор
— 3 пользовательских дескриптора
Фактически тестом можно считать одно проверяемое свойство в спецификации. Тест генерируется из ожидаемых данных спецификации, действительных данных из аксессора и логики сопоставления из дескриптора.
Не знаю как сделано в Code Contract, но в Design By Contract проверка выглядит примерно так (проверки в статическом классе Check):
public double GetParameter( Vector point )
{
Check.Require( !Direction.IsZeroLength, "Направление линии не должно быть вырожденным" );
var t = new List<double>( 2 );
// Параметры t по значимым осям
if( Op.Nz( Direction.X ) )
{
t.Add( ( point.X - Begin.X ) / Direction.X );
}
if( Op.Nz( Direction.Y ) )
{
t.Add( ( point.Y - Begin.Y ) / Direction.Y );
}
// Проверка на то что параметр t существует и корректен
Check.Ensure( t.Count > 0, "Если точка лежит на линии, то у нее должен быть определен параметр" );
Check.Ensure( Op.Eq( t.Max( ), t.Min( ) ), "Разброс значений параметра t не должен быть больше заданной точности" );
// Возвращаем среднее значение
return t.Average( );
}
Своей цели обезопасить программу от неверных данных он служит. Мне Design By Contract в таком виде нравится.
Я слышал только об одном Code Contract — библиотека от MS, которая, кажется, скоро должна выйти. Давно не смотрел, что же она в итоге умеет. Потому что когда ее только объявили, я увидел, что это просто развитие идеи Design-by-Contract от Billy McCafferty — devlicio.us/blogs/billy_mccafferty/archive/2006/09/22/design_2d00_by_2d00_contract_3a00_-a-practical-introduction.aspx. А до него, кстати, это было в языке Eiffel.
В общем, если под Code Contract подразумевается явное указание того, какие данные требуются на входе и выходе метода, то это не интеграционное тестирование. У меня такие проверки есть — класс Utils.Common.Check. Эти проверки не предназначены для тестирования системы — это скорее защита программы от некорректных данных.
en.wikipedia.org/wiki/Software_testing#Non_Functional_Software_Testing
Один и тот же тест можно отнести в разные группы по разным срезам классификаций. Нагрузочное тестирование, как правило, происходит либо при системном тестировании, либо при интеграционном.
Классифицировать можно по разным критериям.
1) Отношение к тестовым данным.
Насколько я понял, тестовые данные всегда задаются в табличном виде. Несколько аргументов и несколько проверяемых критериев. Но что делать в Fitnesse когда тестовые данные — это целый файл? Логично именно файл передавать как данные, если тестируется конвертирование документа в другой формат, к примеру.
У меня тестовые данные находятся либо в самой спецификации, либо в отдельном файле. В обоих случаях файлы хранятся в DLL тестового проекта как Embedded Resource. Это позволяет:
— Включать интеграционные тесты вместе со всеми данными в систему контроля версий.
— Всегда иметь под рукой спецификации и тестовые данные, когда работаешь в студии.
2) Считывание пользовательских типов данных.
Насколько просто в Fitnesse считать из спецификации данные такого вида?
$Vertices =
(0;0) (4;0) (4;3) (0;3)
(0;2) (2;2) (2;3) (0;3)
(0;1) (3;1) (3;3) (0;3)
Это коллекция точек в двумерном пространстве.
Мой движок заточен на расширяемость пользовательскими типами данных.
3) Ориентированность
Для тестирования в Fitness составляются таблицы. У меня же для каждого экземпляра тестовых данных пишется отдельная спецификация. Приблизительно это означает, что каждый ряд из таблицы Fitness разворачивается в спецификацию.
Это отличие продиктовано отношением к тестовым данным. У меня сложилось впечатление, что Fitnesse ориентирован на более низкоуровневое unit-тестирование. У меня же упор на интеграционное. Мне сложно объяснить без демонстрации кода. Скоро опубликую статью про мой движок, там покажу что я имею ввиду.
4) Чистота кода
Мой движок не требует объявлять место хранения для свойств в классе. Такого вида код не встречается (http://schuchert.wikispaces.com/FitNesse.Tutorials.1):
private int channel;
public void setChannel(int channel) {
this.channel = channel;
}
Такой код никому не интересен. Зачем писать служебный код? Он не решает задачу тестирования. В коде должны быть вычисления реальных значения свойств, а данные уже есть в спецификации.
5) Простой тестовый вывод
У меня простой движок, он не генерирует HTML отчеты. У него простой консольный вывод в котором указано все что требуется программисту для исправления ошибки. При тестировании из-под студии консольный вывод сохраняется в результатах прогона теста.
null подсвечивается, а exception по поводу не инициализированного свойства я вижу максимум один раз.
Чтобы кидались исключения когда не инициализирую.
А так да, в общем случае вызывать конструктор по умолчанию полезно.
— API.
— Некоторые диалоги реализованы только под WinForms
— Не нашел Credentials диалога
В Ookii два варианта диалогов — с зависимостью от WinForms библиотек или с зависимостью от WPF. Совместимость с предыдущими виндами нужно проверять на конкретных диалогах.