Тестовое покрытие для многих И / ИЛИ условий в одном утверждении - PullRequest
0 голосов
/ 12 января 2019

Пример оператора:

if (conditionA && conditionB && conditionC && conditionD) {
    return true;
}

Я мог бы написать модульные тесты для всех 2 ^ 4 комбинаций, но это легко вышло бы из-под контроля, если было добавлено больше условий.

Какой должна быть моя стратегия модульного тестирования, чтобы охватить все условия для такого утверждения? Есть ли другой способ сделать код более надежным?

Ответы [ 5 ]

0 голосов
/ 04 мая 2019

В качестве вступления к моему ответу я хотел бы еще раз объяснить, почему мы проводим тестирование программного обеспечения. Большинство испытуемых действительно недопонимают.

  • Мы НЕ тестируем программное обеспечение, чтобы показать, что оно не содержит ошибок (это невозможно. Уже для незначительного сложного программного обеспечения)
  • Мы проводим «конструктивный тест», чтобы доказать, что функциональность приемлема, а требования или функции «работают».
  • И самое главное: мы стараемся найти как можно больше ошибок («Разрушительный тест»). Мы никогда не найдем все ошибки. SRGM может быть применен, чтобы показать, насколько глубоким должно быть тестирование.

Тогда, и это уже ответ на часть вашего вопроса «Какой должна быть моя стратегия юнит-тестирования?»

Я приведу Automotive SPICE (PAM 3.1), хорошо известную и проверенную модель процесса, Process SWE.4, Проверка программного обеспечения:

«Целью процесса проверки программных модулей является проверка программных модулей для предоставления доказательств соответствия программных модулей детальному проектированию программного обеспечения и требованиям к нефункциональному программному обеспечению».

Другой набор описаний модульных испытаний для программного обеспечения с более высокими требованиями к качеству и особенно безопасности можно взять из ISO 26262 «Дорожные транспортные средства - Функциональная безопасность -», Часть 6: Разработка продукта на уровне программного обеспечения », глава 9, таблицы 10, 11, 12

Методы тестирования программного обеспечения

Requirements-based test
Interface test
Fault injection test
Resource usage test
Back-to-back comparison test between model and code, if applicable

Методы получения тестовых случаев для модульного тестирования программного обеспечения

Analysis of requirements
Generation and analysis of equivalence classes
Analysis of boundary values
Error guessing

И теперь, самое важное, отвечая на вторую часть вашего вопроса, вы должны провести структурный анализ покрытия (НЕ структурный тест), чтобы оценить полноту тестовых случаев и продемонстрировать, что непреднамеренная функциональность отсутствует. Никогда не путайте структурные испытания и структурное покрытие.

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

Рекомендуемый показатель покрытия - MCDC.

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

Снова глядя на ваш вопрос:

if (conditionA && conditionB && conditionC && conditionD) 
{
    return true;
}

Кажется, вы запрашиваете рекомендацию для структурного испытания. Я также отвечу на этот вопрос, но помните, что с помощью этого метода вы просто тестируете, правильно ли работает компилятор.

Для имеющегося логического выражения (и других более сложных выражений) вы никогда не найдете одну из следующих ошибок:

Классы ошибок

Expression Negation Fault (ENF)
Sub-Expression Negation Fault (SENF)
Sub-Expression Omission Fault (SEOF)
Literal Negation Fault (LNF)
Literal Omission Fault (LOF)
Literal Reference Fault (LRF)
Literal Insertion Fault (LIF)
Operator Reference Fault (ORF)
Stuck-at-1 Fault (SA1) 
Stuck-at-0 Fault (SA0)
Parenthesis Insertion Fault (PIF)
Parenthesis Omission Fault (POF)
Parenthesis Shift Fault (PSF)

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

Пример: * 1 047 *

Если ваши требования изначально предполагали иметь «И» вместо «И» в вашем выражении (класс ошибок ORF), использование покрытия условий с тестовым вектором «TTTT» и «FFFF» даст вам 100% покрытие условий и 100% решение или покрытие филиала. Но вы не найдете ошибку. MCDC выявит проблему.

Вы также упомянули возможность протестировать все комбинации (MCC, Multiple Condition Coverage). Для 4 переменных это нормально. Но для большего количества переменных продолжительность выполнения теста будет расти геометрически. Это не управляемо. И это было одной из причин, почему MCDC был определен.

Теперь давайте предположим, что ваш пример утверждения верен и вернемся к определению тестовых случаев для структурного теста, основанного на MCDC, для вашего выражения.

Есть несколько определений,В основном речь идет о MCDC «Уникальная причина», игнорируя тот факт, что в то же время «MCDC Masking» и «MCDC« Уникальная причина + »» являются сертифицированными и утвержденными критериями. Для тех, кому нужно забыть обо всех уроках, начиная с представления BlackBox на таблице истинности. Говоря о структурном покрытии или тестировании, должно быть ясно, что будет работать только представление WhiteBox. И если вам случится разрабатывать язык с булевыми сокращенными оценками (как, например, в Java, C или C ++), будет даже более очевидно, что представление WhiteBox является обязательным.


Для вашего логического выражения / решения («abcd») и применения булевой оценки кратчайшего пути существует в общей сложности 16 тестовых пар MCDC с уникальной причиной:

1   Influencing Condition: 'a'  Pair:  0, 15   Unique Cause
2   Influencing Condition: 'a'  Pair:  1, 15   Unique Cause
3   Influencing Condition: 'a'  Pair:  2, 15   Unique Cause
4   Influencing Condition: 'a'  Pair:  3, 15   Unique Cause
5   Influencing Condition: 'a'  Pair:  4, 15   Unique Cause
6   Influencing Condition: 'a'  Pair:  5, 15   Unique Cause
7   Influencing Condition: 'a'  Pair:  6, 15   Unique Cause
8   Influencing Condition: 'a'  Pair:  7, 15   Unique Cause
9   Influencing Condition: 'b'  Pair:  8, 15   Unique Cause
10  Influencing Condition: 'b'  Pair:  9, 15   Unique Cause
11  Influencing Condition: 'b'  Pair: 10, 15   Unique Cause
12  Influencing Condition: 'b'  Pair: 11, 15   Unique Cause
13  Influencing Condition: 'c'  Pair: 12, 15   Unique Cause
14  Influencing Condition: 'c'  Pair: 13, 15   Unique Cause
15  Influencing Condition: 'd'  Pair: 14, 15   Unique Cause

В результате чего рекомендуется набор тестов MCDC (существует более одного решения):

Test Pair for Condition 'a':    0  15   (Unique Cause)
Test Pair for Condition 'b':    8  15   (Unique Cause)
Test Pair for Condition 'c':   12  15   (Unique Cause)
Test Pair for Condition 'd':   14  15   (Unique Cause)

Вектор теста: Окончательный результат: 0 8 12 14 15

 0:  a=0  b=0  c=0  d=0    (0)
 8:  a=1  b=0  c=0  d=0    (0)
12:  a=1  b=1  c=0  d=0    (0)
14:  a=1  b=1  c=1  d=0    (0)
15:  a=1  b=1  c=1  d=1    (1)

Без булевой оценки коротких путей, очевидно, у вас есть только 4 пары тестов MCDC с уникальной причиной:

1  Influencing Condition: 'a'  Pair:  7, 15   Unique Cause
2  Influencing Condition: 'b'  Pair: 11, 15   Unique Cause
3  Influencing Condition: 'c'  Pair: 13, 15   Unique Cause
4  Influencing Condition: 'd'  Pair: 14, 15   Unique Cause

Приводит к одному детерминированному решению:

Тестовый вектор: Окончательный результат: 7 11 13 14 15

 7:  a=0  b=1  c=1  d=1    (0)
11:  a=1  b=0  c=1  d=1    (0)
13:  a=1  b=1  c=0  d=1    (0)
14:  a=1  b=1  c=1  d=0    (0)
15:  a=1  b=1  c=1  d=1    (1)

Надеюсь, я мог бы пролить немного света на этот вопрос.

Если вы хотите изучить MCDC более подробно, с поддержкой инструментов, вы можете взглянуть на

MCDC

0 голосов
/ 12 января 2019

Много было написано по этой теме, и ваш вопрос, похоже, требует MC / DC.

Существует предикат, состоящий из нескольких условий, которые приводят к решению. Хорошо известные критерии покрытия, применяемые к предикату в вопросе, включают:

  1. Охват решения: Убедитесь, что общий предикат один раз равен истинному, а другой - ложному.
    Это приводит к двум контрольным случаям, например (T, T, T, T) и (F, T, T, T).

  2. Базовое условие покрытия: Убедитесь, что каждое условие является истинным и ложным.
    Этого также можно достичь с помощью двух тестовых случаев: (T, T, T, T) и (F, F, F, F).
    Обратите внимание, что базовое условие покрытия не должно подразумевать покрытие принятием решения (пример: "P AND Q" с тестовыми примерами (T, F) и (F, T) соответствует покрытию базового условия, но оба оценивают как F, поэтому не достигают 100% принятие решения).

  3. Модифицированный охват условий / решений ( MC / DC ). Комбинация покрытия решений и базовых условий, «модифицированных», так что для него также требуется каждый условие должно индивидуально определять результат. Ответ Эдвина Бака является действительным покрытием MC / DC (TTTT, FTTT, TFTT, TTFT, TTTF).
    В общем, при N условиях MC / DC требует N + 1 контрольных примеров, а не 2 ^ N. Таким образом, он обеспечивает хороший баланс между строгостью (каждое тестируемое условие) и эффективностью (тестирование всех 2 ^ 4 может не потребоваться). Интуиция, лежащая в основе этого, является именно тем, что ответ Адама Бейтса .

  4. Полный охват условий: Проверка всех 2 ^ N возможных комбинаций.

0 голосов
/ 12 января 2019

То, как я вижу этот сценарий, - это 1 счастливый путь и 4 потенциальных точки отказа. Если каждое условие имеет решающее значение для разрешения возврата true, то было бы разумно написать:

  1. Одиночный модульный тест «счастливый путь», единственный случай, когда логика возвращает истину. И
  2. Юнит-тест для каждой переменной, который может привести к сбою проверки, утверждая, что у одной переменной есть сила, предотвращающая прохождение условия.

Я понимаю, что можно написать логику, которая проходит эти проверки, но на самом деле возвращает истину, когда несколько переменных ложные ... но я действительно не стал бы беспокоиться о таких случаях, если вы не работаете на космическом корабле или чем-то, где жизнь / смерть вовлечена. Практически во всех случаях тестер просто проверяет, что реализация завершается с ошибкой любой переменной.

0 голосов
/ 12 января 2019

Я бы рекомендовал следующий подход

                       A B C D
testTypicalCall()   -> T T T T
testAisFalseFails() -> F T T T
testBisFalseFails(  -> T F T T
testCisFalseFails() -> T T F T
testDisFalseFails() -> T T T F

Здесь фиксируются четыре независимых способа сбоя, и можно сделать вывод, что если два из этих способов произошли в комбинации, то должен сработать хотя бы один из ваших тестов на сбой.

Он также устойчив к перестановке A, B, C и D в будущем рефакторинге операторов if и не использует логику короткого замыкания для гарантии того, что условие сбоя зафиксировано. (Ответ Джастина тоже хорош, но, выбирая истинные значения для непроверенных значений в его решении, вы увеличиваете выразительную силу теста и защищаете от сообщений об ошибках, указывающих неверный неверный параметр, если вы решите каким-либо образом сообщить, какой параметр ложь).

0 голосов
/ 12 января 2019

Возможно, вам не нужно выполнять все 2 ^ 4 условий, поскольку, например, если A ложно, другие условия даже не проверяются. Вы могли бы быть в состоянии уйти с просто 5

    A   B   C   D
    F   X   X   X
    T   F   X   X
    T   T   F   X
    T   T   T   F
    T   T   T   T

Но, как сказал другой Дейв, в зависимости от вашего кода вам может не потребоваться тестировать все ваши условия. Подумайте о цели вашего теста и посмотрите, что подходит

Редактировать: изменение, предложенное avandeursen

...