Я знаю, что это сложный и открытый вопрос, но я решил задать его и узнать, есть ли у кого-нибудь интересные предложения.
Я разработал генератор кода, который берет наш python-интерфейс к нашему C++ коду (сгенерированный через SWIG) и генерирует код, необходимый для экспликации этого кода как WebServices. Когда я разрабатывал этот код, я делал это, используя TDD, но я обнаружил, что мои тесты были чертовски хрупкими. Поскольку каждый тест, по сути, должен был проверить, что для заданного бита входного кода (который, как оказалось, является заголовком C++) я получу заданный бит выводимого кода, я написал небольшой механизм, который читает определения тестов из входных XML-файлов и генерирует тестовые случаи на основе этих ожиданий.
Проблема в том, что я боюсь вообще заходить в код, чтобы его модифицировать. Это и тот факт, что сами юнит-тесты а: сложные и б: хрупкие.
Поэтому я пытаюсь придумать альтернативные подходы к этой проблеме, и мне кажется, что я, возможно, решаю ее неправильно. Возможно, мне нужно больше сосредоточиться на результате, IE: действительно ли код, который я генерирую, работает и делает то, что я хочу, а не на том, выглядит ли код так, как я хочу.
Есть ли у кого-нибудь опыт в чем-то подобном, которым он хотел бы поделиться?
Я начал писать краткое изложение своего опыта работы с собственным генератором кода, затем вернулся и перечитал ваш вопрос и обнаружил, что вы уже сами затронули те же проблемы, сосредоточившись на результатах выполнения, а не на компоновке/внешнем виде кода.
Проблема в том, что это трудно проверить, сгенерированный код может не подходить для реального выполнения в среде системы модульного тестирования, и как закодировать ожидаемые результаты?
Я обнаружил, что нужно разбить генератор кода на более мелкие части и тестировать их. Юнит-тестирование полного генератора кода больше похоже на интеграционное тестирование, чем на юнит-тестирование, если вы спросите меня.
Вспомните это " единица testing" только один вид тестирования. Вам необходимо к модульному тесту внутренние части Вашего генератора объектного кода. Какой you' ре, действительно смотрящее на вот, является системным тестированием уровня (иначе тестирование регресса). It' s не только семантика... есть различные мышления, подходы, ожидания, и т.д. It' s, конечно, больше работы, но Вы, вероятно, должны стиснуть зубы и настроить непрерывный набор тестов регресса: зафиксированный C ++ файлы-> ПОТЯНИТЕ соединяет-> модули питона-> известная продукция. Вы действительно хотите проверить известный вход (зафиксировал C ++ кодекс) против ожидаемой продукции (что выходит из финала программа Пайтона). Проверка результатов генератора объектного кода непосредственно была бы похожа на файлы объекта diffing...
Если вы работаете на *nux, вы можете отказаться от фреймворка unittest в пользу сценария bash или makefile. На windows вы можете создать приложение/функцию оболочки, которая запускает генератор, а затем использует код (как другой процесс) и проводит unittest.
Третьим вариантом может быть генерация кода, а затем создание из него приложения, которое не включает ничего, кроме unittest. Опять же, вам понадобится сценарий оболочки или что-то в этом роде, чтобы запускать его для каждого входа. Что касается того, как закодировать ожидаемое поведение, мне кажется, что это можно сделать примерно так же, как и для кода C++, только используя сгенерированный интерфейс, а не интерфейс C++.
Просто требуемый, чтобы указать, что Вы можете все еще достигнуть мелкозернистого тестирования, проверяя результаты: Вы можете проверить отдельные части кодекса вложением их в некоторой установке и коде подтверждения:
int x = 0;
GENERATED_CODE
assert(x == 100);
Если Вам собрали Ваш произведенный кодекс от меньших кусков, и куски часто не изменяются, Вы можете осуществить больше условий и проверить немного лучше, и надо надеяться постараться не иметь весь свой испытательный разрыв, когда Вы изменяете специфические особенности одного куска.
Модульное тестирование состоит просто в том что, проверяя определенную единицу. Таким образом, если Вы пишете спецификацию для класса A, это идеально, если у класса A нет реальных конкретных версий класса B и C.
Хорошо я заметил впоследствии, что признак для этого вопроса включает C ++ / Пайтон, но принципы - то же:
public class A : InterfaceA
{
InterfaceB b;
InterfaceC c;
public A(InterfaceB b, InterfaceC c) {
this._b = b;
this._c = c; }
public string SomeOperation(string input)
{
return this._b.SomeOtherOperation(input)
+ this._c.EvenAnotherOperation(input);
}
}
Поскольку вышеупомянутая Система A вводит интерфейсы к системам B и C, Вы можете модульный тест просто система A, не имея реальной функциональности, выполняемой никакой другой системой. Это - модульное тестирование.
Вот умный способ для приближения к Системе от создания до завершения с различным Когда спецификация для каждой части поведения:
public class When_system_A_has_some_operation_called_with_valid_input : SystemASpecification
{
private string _actualString;
private string _expectedString;
private string _input;
private string _returnB;
private string _returnC;
[It]
public void Should_return_the_expected_string()
{
_actualString.Should().Be.EqualTo(this._expectedString);
}
public override void GivenThat()
{
var randomGenerator = new RandomGenerator();
this._input = randomGenerator.Generate<string>();
this._returnB = randomGenerator.Generate<string>();
this._returnC = randomGenerator.Generate<string>();
Dep<InterfaceB>().Stub(b => b.SomeOtherOperation(_input))
.Return(this._returnB);
Dep<InterfaceC>().Stub(c => c.EvenAnotherOperation(_input))
.Return(this._returnC);
this._expectedString = this._returnB + this._returnC;
}
public override void WhenIRun()
{
this._actualString = Sut.SomeOperation(this._input);
}
}
Таким образом в заключение единственная единица / у спецификации может быть несколько поведений, и спецификация растет, поскольку Вы развиваете единицу / система; и если Ваша система при тесте зависит от других конкретных систем в нем, предостеречься.
Моя рекомендация состояла бы в том, чтобы выяснить ряд известных результатов ввода - вывода, таких как некоторые более простые случаи, которые Вы уже имеете в распоряжении, и модульный тест кодекс, который является produced. It' s совершенно возможный, что, поскольку Вы изменяете генератор, что точная последовательность, которая произведена, может немного отличаться..., но о чем Вы действительно заботитесь, интерпретируется ли это таким же образом. Таким образом, если Вы проверите результаты, как Вы проверили бы тот кодекс, если бы это была Ваша особенность, Вы узнаете, преуспевает ли это в способах, которыми Вы хотите.
В основном то, что Вы действительно хотите знать, - произведет ли Ваш генератор то, что Вы ожидаете, физически не проверяя каждую возможную комбинацию (также: невозможный). Гарантируя, что Ваш генератор последователен в способах, которыми Вы ожидаете, Вы можете чувствовать себя лучше, что генератор преуспеет в «еще более сложных» ситуациях.
Таким образом Вы можете также создать комплекс тестов на регресс (модульные тесты, которые должны продолжать работать правильно). Это поможет Вам удостовериться, что изменения Вашего генератора - not' t ломка других форм кодекса. Когда Вы сталкиваетесь с ошибкой что Ваши модульные тесты didn' t выгода, Вы можете хотеть включать его, чтобы предотвратить подобную поломку.
Я нахожу, что Вы должны проверить что you' ре, производящее больше, чем, как Вы производите его.
В моем случае программа производит много типов кодекса (C#, HTML, SCSS, JS, и т.д.), которые собирают в веб-приложение. Лучшим способом I' ve, который, как находят, уменьшал ошибки регресса в целом, должен проверить само веб-приложение, не, проверив генератор.
Don' t понимают меня превратно, есть все еще модульные тесты, проверяющие часть кодекса генератора, но наш самый большой удар для нашего доллара был тестами UI на самом произведенном приложении.
С тех пор we' ре, производящее его, мы также производим хорошую абстракцию в JS, который мы можем использовать, чтобы программно проверить приложение. Мы следовали за некоторыми идеями, обрисованными в общих чертах здесь: http://code.tutsplus.com/articles/maintainable-automated-ui-tests - чистые 35089
Большая часть - то, что это действительно проверяет Вашу систему от начала до конца от генерации объектного кода к какой you' ре, на самом деле производящее. Как только тест терпит неудачу, его легкое, чтобы отследить его назад туда, где генератор сломался.
It' s довольно сладкий.
Удачи!