Как создать хорошее покрытие кода логикой с плавающей точкой?
Я создаю новый код вручную. Я хотел бы убедиться, что я не оставлю камня на камне.
Есть ли что-то конкретное, что я могу сделать, кроме указания кодовых контрактов для руководства Pex, чтобы он обеспечивал хорошее покрытие в численно интенсивном коде?
Попробуйте найти http://research.microsoft.com/en-us/projects/pex/pexconcepts.pdf по ключевому слову "float" некоторую справочную информацию.
Арифметические ограничения над числами с плавающей запятой аппроксимируются переводом в рациональные числа, а эвристические методы поиска используются за пределами Z3 для нахождения приближенных решений для ограничений с плавающей запятой.
...а также...
Символическое рассуждение. Pex использует автоматический решатель ограничений, чтобы определить, какие значения актуальны для теста и тестируемого кода. Однако возможности решателя ограничений ограничены и всегда будут ограничены. В частности, Z3 не может точно рассуждать об арифметике с плавающей точкой.
В качестве альтернативы, вы знаете инструмент под.NET, который лучше подходит для задачи поиска числовых аномалий под.NET? Мне известно о http://fscheck.codeplex.com/ но оно не выполняет символические рассуждения.
1 ответ
Вы хотите хорошее освещение? Просто иметь тест, который запускает каждую ветвь в куске кода, вряд ли на самом деле означает, что это правильно - часто речь идет о угловых случаях, и вы, как разработчик, лучше всего знаете, что это за угловые случаи. Это также звучит так, будто работает, просто говоря "вот интересная комбинация ввода", в то время как более вероятно, что вам нужно указать поведение системы, которую вы хотите увидеть - если вы написали код неправильно во-первых, то интересный входные данные могут быть совершенно не связаны с правильным кодом.
Возможно, это не тот ответ, который вы ищете, но я бы сказал, что лучший способ сделать это вручную! Запишите спецификацию до того, как вы начнете кодировать, и включите ее в нагрузку тестовых случаев, когда вы знаете, как пишете API для своего класса / подсистемы.
Когда вы начнете заполнять API/ писать код, вы, вероятно, подберете дополнительные кусочки и кусочки, которые вам нужно сделать + выясните, что такое сложные кусочки - если у вас есть условные выражения и т. Д., Которые, по вашему мнению, кто-то реорганизует в вашем коде может ошибиться, тогда напишите тестовый пример, который охватывает их. Я иногда намеренно пишу код неправильно в этих точках, получаю тест, который проваливается, и затем исправляю его, просто чтобы убедиться, что тест проверяет правильный путь через код.
Затем попробуйте подумать о любых нечетных значениях, которые вы, возможно, не охватили - отрицательные входные данные, нулевые значения и т. Д. Часто это будут недопустимые случаи, и вам не захочется обслуживать / думать о них - в этих случаях я обычно пишу некоторые тесты сказать, что они должны генерировать исключения - это в основном останавливает людей, злоупотребляющих кодом в тех случаях, когда вы не знаете, как правильно / с неверными данными.
Вы упомянули выше, что вы работаете с численно интенсивным кодом - возможно, стоит протестировать уровень выше, чтобы вы могли протестировать поведение в системе, которую вы ищете, а не просто вычислять числа - при условии, что код не является чисто числовым, это будет помочь вам установить некоторые реальные условия выполнения, а также убедиться, что независимо от того, что бит вычисления действительно выполняет, взаимодействует с остальной частью программы так, как вам нужно - если это что-то алгоритмическое, вам, вероятно, будет лучше написать приемочный тест язык, помогающий охарактеризовать желаемые результаты в различных ситуациях - это дает четкое представление о том, чего вы пытаетесь достичь, а также позволяет передавать большие объемы (реальных) данных через систему, которая, вероятно, лучше, чем сгенерированный компьютером вход. Другим преимуществом этого является то, что если вы понимаете, что алгоритм нуждается в радикальной переписке, чтобы выполнить какое-то новое требование, то все, что вам нужно сделать, это добавить новый контрольный пример, а затем переписать / изменить; если бы ваши тесты просто смотрели на детали алгоритма и предполагали влияние на внешний мир, у вас была бы существенная головная боль, пытаясь выяснить, как алгоритм в настоящее время влияет на поведение, какие части были правильными, а какие нет, а затем пытаться перенести загрузку модульных тестов на новый API/ алгоритм.