Data Flow Testing Vrios critrios de adequao at

  • Slides: 24
Download presentation
Data Flow Testing

Data Flow Testing

Vários critérios de adequação até aqui Baseado em entradas de função (funcional) Baseado na

Vários critérios de adequação até aqui Baseado em entradas de função (funcional) Baseado na estrutura do programa (estrutural) Baseado em faltas injetadas (mutação)

Algumas limitações também. . . Funcional Estrutural Inadequado para construir entradas que leva a

Algumas limitações também. . . Funcional Estrutural Inadequado para construir entradas que leva a caminhos específicos do programa Pode gerar muitos caminhos desnecessários (e. g. , exercitar mesmo loop repetidamente. ) Baseado em falhas Modelo de falhas possivelmente irrealista, alto custo de execução de mutantes, alto custo de identificação de programas equivalentes

Critério baseado em fluxo de dados Recordar origem de um bug: Falta modifica estado

Critério baseado em fluxo de dados Recordar origem de um bug: Falta modifica estado de um programa incorretamente Falha manifesta-se através da leitura deste estado Observação Relação de leitura e escrita entre dados é importante!

Critério baseado em fluxo de dados Abordagem Suíte deve incluir testes que executam statements

Critério baseado em fluxo de dados Abordagem Suíte deve incluir testes que executam statements logicamente relacionados E. g. , escrita e posterior leitura de um campo de um objeto devem aparecer em um mesmo teste

DU Pair Associação de definição e uso de variáveis do programa Neste contexto, uma

DU Pair Associação de definição e uso de variáveis do programa Neste contexto, uma definição é uma nova atribuição de valor a uma variável

Exemplo 01: public static int foo(int a) { 02: if (a > 10) {

Exemplo 01: public static int foo(int a) { 02: if (a > 10) { 03: a++; 04: } 05: . . . 06: return a; 07: } Assuma que parâmetro define um valor DU pairs: (01, 02), (01, 03), . . .

Exemplo 01: public static int foo(int a) { 02: if (a > 10) {

Exemplo 01: public static int foo(int a) { 02: if (a > 10) { 03: a++; 04: } 05: . . . // nova definição de a? 06: return a; 07: } DU pairs: (01, 02), (01, 03), (03, 06)? Linha 05 pode redefinir variável a.

DU Path Caminho que associa uma definição ao uso de uma variável Vários DU

DU Path Caminho que associa uma definição ao uso de uma variável Vários DU Paths para um DU Pair E. g. 01: 02: 03: 04: 05: 07: 08: int x = 1; if (. . . ) {. . . } else {. . . } System. out. println(“x value”+ x);

Cobertura de uma suíte de testes du pairs: fração de todos os pares du

Cobertura de uma suíte de testes du pairs: fração de todos os pares du que são cobertos por pelo menos um teste du paths: fração de todos os caminhos (desconsiderando loop) du que são cobertos por pelo menos um teste definitions: fração de definições cobertas por pelo menos um teste

Desafios gerais de análises estáticas Abrangência: whole-program analysis, main Profundidade: intraprocedural, interprocedural Características de

Desafios gerais de análises estáticas Abrangência: whole-program analysis, main Profundidade: intraprocedural, interprocedural Características de programas: encapsulamento de dados, ponteiros e arrays

Interprocedural public class Sample { int x; public static void main(String[] args){ Sample s

Interprocedural public class Sample { int x; public static void main(String[] args){ Sample s = new Sample(); s. x = read(System. in); if (s. x > 10) { s. x--; } s. f(); } public void f() { s. x++; } } Definição de s. x se propaga até Sample. f

Interprocedural public class Sample { int x; public static void main(String[] args){ Sample s

Interprocedural public class Sample { int x; public static void main(String[] args){ Sample s = new Sample(); s. x = read(System. in); if (s. x > 10) { s. x--; } s. f(); } public void f() { s. x++; } } Definição de s. x se propaga até Sample. f Duas definições alcançam a entrada de f

Interprocedural public class Sample { int x; public static void main(String[] args){ Sample s

Interprocedural public class Sample { int x; public static void main(String[] args){ Sample s = new Sample(); s. x = read(System. in); if (s. x > 10) { s. x--; } s. f(); } public void f() { s. x++; } } Definição de s. x se propaga até Sample. f Duas definições alcançam a entrada de f Análise é feita sobre funções alcançáveis a partir de main

Análise a partir de função main Reduz complexidade da análise estática No contexto de

Análise a partir de função main Reduz complexidade da análise estática No contexto de testes é útil para medir cobertura Muitas funções não são alcançáveis (usadas) Requisitos de teste (cobertura) são construídos a partir de uma sequência de teste Mas desconsidera vários comportamentos

Análise a partir de função main Reduz complexidade da análise estática No contexto de

Análise a partir de função main Reduz complexidade da análise estática No contexto de testes é útil para medir cobertura Muitas funções não são alcançáveis (usadas) Requisitos de teste (cobertura) são construídos a partir de uma sequência de teste Mas desconsidera vários comportamentos Nota: as vezes, não há uma função main a analisar

Alternativa: construção de contextos Mas que contextos são esses? (além de main) Heurística para

Alternativa: construção de contextos Mas que contextos são esses? (além de main) Heurística para OO: assuma que métodos de uma classe estão relacionados

Várias funções e encapsulamento public class Stack<T> { int num; T[] elems; public void

Várias funções e encapsulamento public class Stack<T> { int num; T[] elems; public void push(T t) { num++; elems[num]=t; } public T pop() { elems[num] = null; num--; } public T peek() { return elem[num]; } }

Várias funções e encapsulamento definições e uso public class Stack<T> { int num; T[]

Várias funções e encapsulamento definições e uso public class Stack<T> { int num; T[] elems; public void push(T t) { num = num + 1; elems[num]=t; } public T pop() { elems[num] = null; num = num - 1; } public T peek() { return elem[num]; } }

Note que não há função main associando peek, push, e pop.

Note que não há função main associando peek, push, e pop.

Encapsulamento de dados public class Stack<T> { int num; T[] elems; public void push(T

Encapsulamento de dados public class Stack<T> { int num; T[] elems; public void push(T t) { num++; . . . } public T pop() {. . . ; num--; } public T peek() { return elem[num]; } } Foo. foo usa definições construídas em Foo. bar. public class Foo { Stack<? > s; public Stack<? > get. Stack() { return s; } public void foo() {. . . get. Stack(). peek(); . . . } public void bar(int k) {. . . get. Stack(). push(k); . . . } }

Encapsulamento de dados public class Stack<T> { int num; T[] elems; public void push(T

Encapsulamento de dados public class Stack<T> { int num; T[] elems; public void push(T t) { num++; . . . } public T pop() {. . . ; num--; } public T peek() { return elem[num]; } } Foo. foo usa definições construídas em Foo. bar. public class Foo { Stack<? > s; public Stack<? > get. Stack() { return s; } public void foo() {. . . get. Stack(). peek(); . . . } public void bar(int k) {. . . get. Stack(). push(k); . . . } } Campo do tipo Stack<? > é estado encapsulado em Foo.

Encapsulamento de dados public class Foo { Stack<? > s; public Stack<? > get.

Encapsulamento de dados public class Foo { Stack<? > s; public Stack<? > get. Stack() { return s; } public void foo() {. . . get. Stack(). peek(); . . . } public void bar(int k) {. . . get. Stack(). push(k); . . . } } public class Foo 2 { Stack<? > s 2; public Stack<? > get. Stack 2() { return s 2; } public void foo 2() {. . . get. Stack(). peek(); . . . } public void bar 2(int k) {. . . get. Stack(). push(k); . . . } } Note, porém, que bar e foo 2 (ou bar 2 e foo) não estão associados!

Leituras adicionais Capítulo 13 (Data Flow Testing) do livro “Software Testing and Analysis” “Efficient

Leituras adicionais Capítulo 13 (Data Flow Testing) do livro “Software Testing and Analysis” “Efficient Computation of Interprocedural Definition-Use Chains”, M. J. Harrold and M. L. Soffa, ACM TOPLAS 1994 Nota: análise que consideram encapsulamento ainda são poucas!