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

В любом случае, при обновлении до 12.2 вы захотите протестировать весь свой код, чтобы убедиться, что он работает должным образом. Отсюда возникает вопрос:

«Какая часть моего кода действительно выполнялась при тестировании?»

Показатели охвата очень помогут в этом.

Простого анализа тестов на уровне строк недостаточно. Чтобы понять, почему, рассмотрим следующий код:

У нас есть базовая функция, которая возвращает свой аргумент и вызывает dbms_output.

Процедура вызывает функцию дважды в одном операторе if:

create or replace function f (p int) 
  return int as 
begin 
  dbms_output.put_line('Executed: ' || p); 
  return p; 
end; 
/ 
create or replace procedure p is 
begin 
  if f(1) = 1 or f(2) = 2 then 
    dbms_output.put_line('this'); 
  else 
    dbms_output.put_line('that'); 
  end if; 
end p; 
/

Из-за оценки короткого замыкания f (2) никогда не выполняется! Вы можете увидеть это на выходе:

SQL> exec p; Executed: 1 this

Все, что работает на линейном уровне, будет неправильно сообщать об этом как о полном покрытии.

Чтобы преодолеть это, вам нужно подробно изучить выполнение «базового блока».

Так что же такое «базовый блок»?

Это фрагмент кода, который вы либо выполняете полностью, либо не выполняете совсем. Код всегда принадлежит ровно одному базовому блоку. Например:

if f(1) = 1 or f(2) = 2 then 
  dbms_output.put_line('this'); 
else 
  dbms_output.put_line('that'); 
end if;

имеет четыре основных блока. Один для каждого вызова f и два для вызовов dbms_output.put_line.

Новая функция покрытия кода измеряет эти базовые блоки и сообщает о них.

Пользоваться им просто. Для начала нужно создать таблицы покрытия для хранения метрик:

exec dbms_plsql_code_coverage.create_coverage_tables;

Затем вызовите start_coverage перед тестом и stop_coverage после:

declare 
  run_id pls_integer; 
begin 
  run_id := dbms_plsql_code_coverage.start_coverage('TEST'); 
  p; 
  dbms_plsql_code_coverage.stop_coverage; 
end; 
/

Затем вы можете получить метрики, запросив таблицы dbmspcc *, которые содержат эти данные:

select owner, name, type, 
       round( ( sum(covered)/count(*) * 100), 2) pct_covered 
from   dbmspcc_runs r 
join   dbmspcc_units u 
on     r.run_id = u.run_id 
join   dbmspcc_blocks b 
on     r.run_id = b.run_id 
and    u.object_id = b.object_id 
where  r.run_comment = 'TEST' 
group by owner, name, type; 
OWNER NAME  TYPE       PCT_COVERED 
----- ----- ---------- ----------- 
CHRIS P     PROCEDURE           50 
CHRIS F     FUNCTION           100

Это все хорошо. Но всегда есть код, который не покрывают ваши тесты. Возможно, он устарел, поэтому вам не нужно его тестировать. Или это код «на всякий случай», охватывающий теоретически возможные, но практически невозможные случаи. Например, печально известный обработчик исключений «когда другие».

Вы хотите исключить эти разделы из своих отчетов. К счастью, вы можете это сделать с помощью прагмы покрытия. Отметив строки как «NOT_FEASIBLE», вы можете отфильтровать их из своих отчетов:

create or replace procedure p is 
begin 
  if f(1) = 1 or f(2) = 2 then 
    dbms_output.put_line('this'); 
  else 
    pragma coverage ('NOT_FEASIBLE'); 
    dbms_output.put_line('that'); 
  end if; 
end p; 
/

Перезапустите тесты, и вы сможете скрыть непроверяемые части в своем отчете!

select owner, name, type, 
       round( ( sum(covered)/count(*) * 100), 2) pct_covered 
from   dbmspcc_runs r 
join   dbmspcc_units u 
on     r.run_id = u.run_id 
join   dbmspcc_blocks b 
on     r.run_id = b.run_id 
and    u.object_id = b.object_id 
where  r.run_comment = 'TEST' 
and    b.not_feasible = 0 
group  by owner, name, type; 
OWNER NAME TYPE      PCT_COVERAGE 
----- ---- --------- ------------ 
CHRIS P    PROCEDURE        66.67 
CHRIS F    FUNCTION           100

Если вы действительно хотите, вы можете исключить целые разделы кода, заключив его в две прагмы покрытия. Первый стартовый NOT_FEASIBLE_START, второй NOT_FEASIBLE_END:

begin S
  pragma coverage ('NOT_FEASIBLE_START'); 
  a_section(); 
  of_untestable_code(); 
  pragma coverage ('NOT_FEASIBLE_END'); 
end; 
/

Полная статья изначально опубликована на сайте blogs.oracle.com 10 ноября 2016 г.