Тестовые случаи White-Box со 100% охватом кода - PullRequest
0 голосов
/ 06 марта 2019

Я прошу прощения, поскольку я очень плохо знаком с тестированием программного обеспечения. Но у меня есть то, что выглядит как простой код для создания тестовых случаев White-box со 100% охватом кода:

01 public class ShapeAreas {
02
03 public double oneParameter(String shape, float x1)
04 {
05     float area;
06     if (shape.equals("A"))
07         return x1 * x1 * Math.XI;
08     else if (shape.equals("B"))
09         return x1 * x1;
10     else 
11         return -1.0;
12 }
13 
14 public double twoParameter(String shape, float x1, float x2)
15 {
16     float area;
17     if (shape.equals("N"))
18         return x1 * x2;
19     else if (shape.equals("M"))
20         return 0.5 * x1 * x2;
21     else
22         return -1.0;
23 }
24 }

Мне нужна помощь в том, как должны выглядеть мои входные данные в этом коде, чтобы достичь 100% покрытия кода при наименьшем количестве тестовых случаев.

Я ценю любую помощь, которую я могу получить, спасибо!

Ответы [ 2 ]

1 голос
/ 09 марта 2019

Я воспользовался свободой добавления номеров строк в ваш код, чтобы иметь возможность дать лучшее объяснение.В комментариях вы упомянули, что вы заинтересованы в освещении заявления.Операторы в ваших примерах кода находятся в строках 07, 09 и 11, а также в 18, 20 и 22. И, конечно, сами операторы if также являются операторами (отсюда и название), но они все равно будут выполняться впри каждом выполнении соответствующей функции.

При одном выполнении функции oneParameter будет выполняться ровно один из условных операторов: либо в строке 07, либо в строке 09, либо в строке 11. Это происходит из-заисключительный характер заявления if-else if-else.Аналогично, при одном вызове функции twoParameter будет выполняться либо оператор в строке 18, либо в строке 20, либо в строке 22.

Следовательно, чтобы охватить все операторы, необходимо вызвать каждую функциютри раза.Аргумент, который управляет фактической взятой ветвью, является в обоих случаях аргументом shape.Это означает, что значение других аргументов не имеет отношения к тому, какой оператор будет выполняться.Тривиальный набор вызовов может быть следующим:

oneParameter("A", 0.0);
oneParameter("B", 0.0);
oneParameter("any other", 0.0);
twoParameter("N", 0.0, 0.0);
twoParameter("M", 0.0, 0.0);
twoParameter("any other", 0.0, 0.0);

Это пример минимального набора вызовов, который обеспечит 100% покрытие операторов.Что может быть удивительным, так это то, что это всего лишь звонки - даже нет оценки результатов.Когда мы говорим о тестовом покрытии, подразумевается, что соответствующие строки кода не только выполняются, но и что соответствующие результаты оцениваются как часть теста.Тогда это может выглядеть следующим образом:

assertEquals(0.0, oneParameter("A", 0.0));
assertEquals(0.0, oneParameter("B", 0.0));
assertEquals(-1.0, oneParameter("any other", 0.0));
assertEquals(0.0, twoParameter("N", 0.0, 0.0));
assertEquals(0.0, twoParameter("M", 0.0, 0.0));
assertEquals(-1.0, twoParameter("any other", 0.0, 0.0));

Несмотря на тот факт, что теперь он имеет 100% охват заявлений и также выполняет оценку результатов, он все еще далек от того, чтобы быть высококачественным набором тестов.Причина в следующем: модульное тестирование обычно выполняется с основной целью поиска ошибок в коде.Однако приведенный выше набор тестов не совсем подходит для поиска каких-либо интересных ошибок.Чтобы дать вам несколько примеров возможных ошибок, которые этот набор тестов не найдет:

  • По ошибке были заменены вычисления в функции oneParameter для "A" и "B".
  • В функции twoParameter для "N" операция * была ошибочно заменена на +.
  • В функции twoParameter для "N" вместо умножения x1 на x2, выражение умноженное x1 на x1.
  • В функции twoParameter для "M" константа была установлена ​​на 0.05 вместо правильного 0.5.

Это всего лишь примеры возможных ошибок.Поэтому для того, чтобы серьезно отнестись к поиску возможных ошибок, нужно думать не только о покрытии.На самом деле, могут быть даже части кода, которые вообще не подходят для тестирования с помощью модульного тестирования - хотя в вашем простом примере это не так.Примерами таких частей кода являются недостижимый код (например, ветвь по умолчанию оператора switch, добавленного для устойчивости) или код, который состоит только из взаимодействий с другими компонентами, и в этом случае тестирование интеграции является более подходящим подходом.Поэтому достижение 100% охвата зачастую не имеет смысла, даже если вы искренне стремитесь получить пакет качественных юнит-тестов.

Охват, тем не менее, является ценной информацией для разработчиков, которые заинтересованы в том, чтобы они рассмотрели все соответствующие сценарии в своем коде.К сожалению, охват гораздо менее ценен, если судить о качестве набора тестов с управленческой точки зрения: в этом контексте он часто сводится к простому проценту, и разработчики вынуждены создавать тесты, пока не будет достигнут определенный процент охвата.- но достаточно часто, не давая им достаточной подготовки, времени и поддержки, чтобы правильно провести тестирование.Как следствие, чтобы достичь покрытия, скажем, 80%, весь тривиальный код (геттеры и сеттеры и т. П.) Может быть «протестирован» для увеличения охвата.Однако тестирование самого сложного и трудного для тестирования 20% кода откладывается из-за нехватки времени (хотя это, вероятно, код, в котором скрыты ошибки).И даже те 80%, которые были покрыты, могут быть протестированы плохо, как с минимальным набором тестов, который я показал выше.

0 голосов
/ 06 марта 2019

Вы должны искать ответвления в каждом из методов, чтобы получить 100% охват. Это A, B, X как параметр shape для метода oneParameter и N, M, X для метода twoParameter.

3 теста для каждого метода обеспечат вам 100% охват.

Однако, это не скажет вам, что ваш код на 100% правильный.

Попробуйте, например, null как форма. (Что приведет к NullpointerException)

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

public void testOneParameterWithShapeB() {
  double result = sut.oneParameter("B", 1.0);
  //TODO check the result
}
...