Macros e asserts
A macro TEST_CASE
Na macro TEST_CASE, fica a escrita do caso de teste em si. Isto é, as chamadas as macros de ASSERT.
O primeiro argumento passado a TEST_CASE, é o nome do caso de teste e o segundo argumento (opcional) é o nome da classe do caso de teste. Se não quiser informar, o caso de teste é vinculado a classe de nome "default" e, a virgula após o nome do caso de teste é obrigatória, mesmo que, após a virgula, não seja definido o nome da classe do caso de testes. Veja o exemplo abaixo:
TEST_CASE( primeiroTeste, MeusTestes ) {
ASSERT_EQUALS( 1, 1, );
}
As macros de assert
As macros de assert suportam uma mensagem personalizada a ser mostrada no caso do assert falhar e, nas versões mais recentes, precisam obrigatoriamente serem finalizadas com um ponto e vírgula.
A macro ASSERT_EQUALS
A macro de assert pode ser utilizada para testar se dois valores são iguais. Exemplos:
ASSERT_EQUALS( 1, 1, );
int a = 1;
int b = 1;
string c = "teste";
string d = "teste";
ASSERT_EQUALS( a, b, );
ASSERT_EQUALS( c, d, As strings não são iguais! );
No exemplo acima, são comparadas duas variáveis inteiras e duas variáveis tipo string. Perceba que no último assert, é passada como terceiro argumento, uma mensagem. Essa mensagem é mostrada, apenas se o assert falhar. Perceba que a mensagem não está entre aspas duplas. As aspas duplas não são necessárias. Caso contrário, as aspas duplas também são impressas.
Perceba também que, os asserts sem a mensagem a ser mostrada em caso de falha, têm uma virgula após os parâmetros e antes do fecha parenteses. Essa virgula é necessária, mesmo que o terceiro argumento não seja informado. Isso vale para todas as macros de assert e a macro TEST_CASE.
A macro ASSERT_NOT_EQUALS
É o contrário da macro ASSERT_EQUALS. Isto é, falha se os valores forem iguais. Exemplo:
string str1 = "teste";
string str2 = "teste2";
ASSERT_NOT_EQUALS( str1, str2, );
A macro ASSERT_EQUALS_ARRAYS
A macro ASSERT_EQUALS_ARRAYS pode ser utilizada para testar se dois arrays são iguais. Exemplo:
int arr1[] = { 1, 2, 3 };
int arr2[] = { 1, 2, 3 };
ASSERT_EQUALS_ARRAYS( arr1, arr2, 3, );
Os asserts de arrays recebem um terceiro parâmetro adicional: o tamanho do array. No exemplo acima, os arrays têm 3 elementos cada.
A macro ASSERT_NOT_EQUALS_ARRAYS
A macro ASSERT_NOT_EQUALS_ARRAYS pode ser utilizada para testar se dois arrays são diferentes. Exemplo:
int arr1[] = { 1, 2, 3 };
int arr2[] = { 3, 2, 1 };
ASSERT_EQUALS_ARRAYS( arr1, arr2, 3, );
A macro ASSERT_EQUALS_VECTORS
A macro ASSERT_EQUALS_VECTORS pode ser utilizada para testar se dois vectors são iguais. Exemplo:
vector vect1 = { 1, 2, 3 };
vector vect2 = { 1, 2, 3 };
ASSERT_EQUALS_VECTORS( vect1, vect2, );
A macro ASSERT_NOT_EQUALS_VECTORS
A macro ASSERT_NOT_EQUALS_VECTORS pode ser utilizada para testar se dois vectors são diferentes. Exemplo:
vector vect1 = { 1, 2, 3 };
vector vect2 = { 3, 2, 1 };
ASSERT_NOT_EQUALS_VECTORS( vect1, vect2, );
Atenção
Você pode desabilitar, ou habilitar, a impressão dos vetores no caso de falha no assert. Isso é útil para evitar impressão de vetores, caso eles tenham muitos elementos, por exemplo.
Para habilitar, ou desabilitar a impressão de vetores (ou arrays) na falha do assert, utilize a seguinte função:
xutest::set_print_vectors( true ); // Para habilitar
xutest::set_print_vectors( false ); // para desabilitar
Esta função set_print_vectors está no header "xutest.h" e no namespace xutest. Agora, veja abaixo dois exemplos:
xutest::set_print_vectors( true ); // Para habilitar
vector vect1 = { 1, 2, 3 };
vector vect2 = { 3, 2, 1 };
ASSERT_EQUALS_VECTORS( vect1, vect2, );
Os vetores são impressos, pois, o assert falha e a flag de impressão de vetores está setada para true. Setada através do método set_print_vectors
xutest::set_print_vectors( false ); // Para desabilitar
vector vect1 = { 1, 2, 3 };
vector vect2 = { 3, 2, 1 };
ASSERT_EQUALS_VECTORS( vect1, vect2, );
Os vetores não são impressos, pois, apesar de o assert falhar, a flag de impressão de vetores está setada para false.
A macro ASSERT_TRUE
A macro assert true testa se uma condição é verdadeira. Exemplo:
int a = 1;
ASSERT_TRUE( a > 0, );
A macro ASSERT_FALSE
A macro assert false testa se uma condição é falsa. Exemplo:
int a = 1;
ASSERT_FALSE( a == 0, );
A macro ASSERT_NULL
A macro ASSERT_NULL testa se o ponteiro aponta para nullptr ou NULL. Exemplo:
string* strptr = nullptr;
ASSERT_NULL( strptr, );
A macro ASSERT_NOT_NULL
A macro ASSERT_NOT_NULL testa se o ponteiro não aponta, nem para nullptr, nem para NULL. Exemplo:
string* strptr = new string( "abc" );
ASSERT_NOT_NULL( strptr, );
A macro ASSERT_THROWS
A macro ASSERT_THROWS testa se uma determinada exceção foi lançada. Exemplo:
ASSERT_THROWS( runtime_error, {
// Código qualquer
throw runtime_error( "XXX" ); // lança uma runtime_error
}, );
A macro ASSERT_NOT_THROWS
A macro ASSERT_THROWS testa se uma determinada exceção não foi lançada. Exemplo:
ASSERT_NOT_THROWS( runtime_error, {
// Código qualquer
}, );
O assert passa se o código dentro do bloco de código do ASSERT_NOT_THROWS não lançar uma exceção "runtime_error".
Chamadas de funções como parâmetro para os asserts
A chamada de funções como parâmetro dos asserts é desencorajada porque a função chamada como parâmetro da macro pode ser executada mais de uma vez na execução da macro, o que pode gerar um efeito estranho.
Então, imagine o caso de teste de uma função de remover sempre o primeiro elemento em uma lista encadeada e retornar o elemento removido (uma operação de pop)!
Não faça conforme a seguir:
ASSERT_NOT_NULL( pop( &lista ), );
No caso acima, a função pop é executada duas vezes porque a macro ASSERT_NOT_NULL, faz referência ao parâmetro dela duas vezes dentro do corpo da macro. Então, a função pop é executada duas vezes, removendo, não apenas o primeiro elemento, mas, os dois primeiros, em um único assert.
O correto é fazer como a seguir e garantir que a função pop será executada apenas uma vez:
Elemento* removido = pop( &lista );
ASSERT_NOT_NULL( removido, );
Nesse caso, a função pop é executada apenas uma vez, fora da chamada a macro ASSERT_NOT_NULL. O que é o comportamento desejado. Isso porque, a macro recebe um valor constante ou variável, não uma chamada a função!
As macros BEFORE_ALL e AFTER_ALL
As macros BEFORE_ALL e AFTER_ALL, podem ser usadas para definir um bloco de código que deve ser executado antes de todos os testes da classe, ou, após todos os testes da classe, respectivemante.
A macro BEFORE_ALL
A macro BEFORE_ALL pode ser usada para definir o que deve ser executado antes de todos os testes da classe de casos de teste. Exemplo:
BEFORE_ALL( MeusTestes ) {
cout << "Iniciando os testes da classe de testes MeusTestes" << endl;
}
TEST_CASE( teste1, MeusTestes ) {
ASSERT_EQUALS( 1, 1, );
}
TEST_CASE( teste2, MeusTestes ) {
ASSERT_TRUE( true, );
}
A mensagem do "cout" da definição BEFORE_ALL, é impressa antes de todos os testes da classe MeusTestes.
A macro AFTER_ALL
A macro AFTER_ALL pode ser usada para definir o que deve ser executado depois de todos os testes da classe de casos de teste. Exemplo:
AFTER_ALL( MeusTestes ) {
cout << "Finalizando os testes da classe de testes MeusTestes" << endl;
}
A mensagem do "cout" da definição AFTER_ALL, é impressa após de todos os testes da classe MeusTestes.
As macros BEFORE_EACH e AFTER_EACH
As macros BEFORE_EACH e AFTER_EACH, podem ser usadas para definir um bloco de código que deve ser executado antes de cada caso de teste da classe, ou, após cada caso de teste da classe, respectivemante.
A macro BEFORE_EACH
A macro BEFORE_EACH pode ser usada para definir o que deve ser executado antes de cada caso de teste da classe de casos de teste. Exemplo:
BEFORE_EACH( MeusTestes ) {
cout << "Iniciando execução do caso de teste" << endl;
}
A mensagem do "cout" da definição BEFORE_EACH, é impressa antes de cada caso de teste da classe MeusTestes.
A macro AFTER_EACH
A macro AFTER_EACH pode ser usada para definir o que deve ser executado depois de cada caso de teste da classe de casos de teste. Exemplo:
AFTER_EACH( MeusTestes ) {
cout << "Finalizando a execução do caso de teste" << endl;
}
A mensagem do "cout" da definição AFTER_EACH, é impressa após de cada caso de teste da classe MeusTestes.
Próxima aula
O próxima aula ensina como criar um exemplo completo de uma calculadora.