Programadores familiarizado com Javascript, porém sem/pouca experiencia em unit test.
Esse post irá abordar vários casos de testes e como eles podem ser testados, de uma forma bem direta e objetiva.
Como hoje existe vários bibliotecas para realizar unit test, cada um tem suas características, os exemplos usado neste artigo será usado Jasmine, porém todos eles podem ser realizados em outras bibliotecas de unit test também.
Para verificar se o resultado do retorno da função é igual a tal valor, existe a função toEqual
, essas funções que vem acompanhados dos expect
, são chamados de matchers
, existe muits outras além do toEqual
na documentação.
const sum = (value1, value2) => value1 + value2;
describe("Testando retorno da funcao", () => {
it("deve retornar a soma dos valores 1 e 2", () => {
const result = sum(1, 2); // pegando resultado da soma de 1 e 2
expect(result).toEqual(3); // verificar se o resultado retornado é igual a 3
});
});
O Jasmine oferece a função objectContaining
, que serve para verificar se tal JSON possui certa propriedade.
function concatObject(obj1, obj2) {
return { ...obj1, ...obj2 };
}
describe("JSON contains propriedade", () => {
it("deve conter CPF no retorno", () => {
const pessoa = { nome: "Paulo", idade: 18 };
const result = concatObject( pessoa, { cpf: "123.456.789-10" } );
expect( result ).toEqual( jasmine.objectContaining( { cpf: "123.456.789-10" } ));
});
});
Verificar se a função esta executando outra funções corretamente.
import $ from "jquery";
function fetchUsers() {
$.get("/my/api/to/get/users", (res) => {
// faz alguma coisa
});
}
describe("Testando se a funcao foi chamado", () => {
it("deve chamar funcao get do jquery", () => {
spyOn($, "get"); // tornar a funcao $.get possivel de ser analisado
fetchUsers();
expect($.get).toHaveBeenCalled(); // verificar se o $.get foi chamado, após a execução da função getUsers
});
});
A função spyOn
irá tornar o função $.get
possivel de ser monitorado, após a chamada da função fetchUsers
, é possivel verificar com toHaveBeenCalled
, se a função realmente foi executado.
Para verificar quantas vezes a função foi executado, o Jasmine oferece a função .calls.count()
, que retorna a quantidade de vezes que a função foi executado.
describe("Testando funcao", () => {
it("A funcao deve ser executado 3 vezes", () => {
const somaFake = jasmine.createSpy("contaFake");
[1, 2, 3].reduce(somaFake, 0);
expect(somaFake.calls.count()).toEqual(3);
});
});
jasmine.createSpy
irá criar uma função monitoravel com algumas funções que ajuda o teste, entre elas o .calls.count()
. Verifique outras funções na documentação do Jasmine
Para ser mais específico, também é possivel verificar quais parametros foram passados para a função chamado.
import $ from "jquery";
const callback = (res) => {
// faz alguma coisa
};
function getUsers() {
$.get("/my/api/to/get/users", callback);
}
describe("Testando se a funcao foi chamado", () => {
it("deve chamar funcao get do jquery", () => {
spyOn($, "get"); // tornar a funcao $.get possivel de ser analisado
getUsers();
expect($.get).toHaveBeenCalledWith("/my/api/to/get/users", callback);
});
});
A função toHaveBeenCalledWith
verifica se os parâmetros recebidos são os mesmos recebido pela função $.get
.
O pacote react-dom
possui as funções para renderização e testes de componentes.
import TestUtils from 'react-dom/test-utils';
const MeuComponente = (props) => {
return <div>
<input className="campo-nome" type="text" value={props.nome} />
Hello {props.nome}
</div>
};
describe("Testando componente com ReactTestUtils", () => {
it("o campo de nome deve conter o nome recebido na propriedade", () => {
const element = TestUtils.renderIntoDocument(<MeuComponente nome="John" />);
expect(TestUtils.findRenderedDOMComponentWithClass(elemento, "campo-nome").value).toEqual("John");
});
});
Após da renderização com a função renderIntoDocument
, é possivel obter o elemento com class campo-nome
utilizando a função findRenderedDOMComponentWithClass
e testando o valor do campo de texto.
Geralmente os componentes do React se comportam conforme as propriedades recebida, nesse caso pode ser usado o mock da propriedade para testar os diversos comportamentos do componente.
Existe a biblioteca enzyme
, que é recomendado no próprio site oficial do React, usado para renderizar o componente React com objetivo de teste.
import { shallow } from "enzyme";
const MeuComponente = (props) => {
return <div>
Hello {props.nome}
</div>
};
describe("Testando componente com propriedades mock", () => {
it("deve conter Hello John", () => {
const wrapper = shallow(<MeuComponente nome="John" />);
expect(wrapper.text()).toEqual("Hello John");
});
});
Quando precisa testar as funções dos componentes, é muito comum criar uma instancia nova do componente para cada teste, garantindo que o estado inicial dos testes, para evitar o trabalho repetitivo de instanciar componente, existe a função beforeEech
:
import React, {Component } from "react";
import { shallow } from "enzyme";
class MeuComponente extends Component {
construct(props) {
super(props);
this.state = {
nome: props.nome
};
this.sayHi = this.sayHi.bind(this);
}
mudarNome(nome) {
this.setState({ nome });
}
render() {
return <div>
Hello {this.state.nome}
</div>
}
}
describe("Criando instancia nova do componente para cada teste de componente", () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<MeuComponente nome="John" />);
});
it("deve conter Hello Paul", () => {
wrapper.instance().mudarNome("Paul");
expect(wrapper.text()).toEqual("Hello Paul");
});
it("deve conter Hello John", () => {
expect(wrapper.text()).not.toEqual("Hello John");
});
});
Para esse teste, foi feito a alteração no componente MeuComponente
para exibir o state.nome
, envez de props.nome
, e pode notar que no primeiro teste, o nome foi alterado de John
para Paul
, mas o segundo teste permanece sucedido, isso é por que o componente foi instanciado novamente antes de executar o código de teste.
Além de beforeEach
, também existe afterEach
, beforeAll
e afterAll
.