Escolar Documentos
Profissional Documentos
Cultura Documentos
Fixture-Factory
Criando objetos para seus testes
Como criar objetos através de templates para serem utilizados
como massa de dados em seus testes.
/ 26
Nykolas Laurentino de Lima | nykolas.lima@gmail.com
É programador na Amil, trabalha com Java há mais de 4 anos. Certificado SCJP e SCWCD.
27 \
Na Listagem 1 nós criamos dois templates para a
classe Client, um deles se chama geekClient e o ou- add(“country”, “Brazil”);
tro nerdClient. Note que podemos utilizar placehol- add(“zipCode”, “0660800”);
ders para criar valores de uma propriedade a partir }});
de outra propriedade, como foi feito na propriedade Fixture.of(Phone.class).addTemplate(
“brazilianPhoneNumber”, new Rule() {{
e-mail. Mais abaixo será explicado o uso de funções
add(“number”, “11 9999-9999”);
para gerar valores dinamicamente na criação do ob- }});
jeto. Fixture.of(Client.class).addTemplate(“geekClient”,
Para obter uma instância do template criado só new Rule() {{
precisamos informar a classe desejada e o nome do //...
template: add(“address”, one(Address.class, “brazilianAddress”));
add(“phones”, has(3).of(Phone.class,
Listagem 2. A Listagem 2 exemplifica a codificação “brazilianPhoneNumber”));
para obter uma instância da classe Client através do //...
template “geekClient“. }});
Fixture.from(Client.class).gimme(“geekClient”);
A função one irá criar uma instância da classe Address
utilizando o template “brazilianAddress” que foi
Um exemplo do objeto gerado para o template criado logo acima.
“geekClient” pode ser visto na figura 1. A propriedade phones é uma lista de telefones,
portanto utilizamos a função has e dizemos para ela
quantas instâncias nós queremos, de qual classe e
qual template será utilizado.
Agora ao obtermos uma instância do template
“geekClient”, automaticamente serão criados os re-
lacionamentos com Address e Phone utilizando os
templates declarados.
Um exemplo dos relacionamentos criados pode
Figura 1. Exemplo de objeto gerado para o template “geekClient”. ser visto na figura 2.
Functions
Relacionamentos As Functions são utilizadas para gerar valores di-
Tratar os relacionamentos entre os objetos tam- nâmicos para as propriedades de um objeto. As Rela-
bém pode ser feito de maneira simples e fácil através tionFunctions explicadas na seção anterior exempli-
das RelationFunctions. ficam a geração de objetos para os relacionamentos,
mas existem outras funções para auxiliar na criação
Listagem 3. A Listagem 3 exemplifica a codificação
de valores simples.
das Relation Functions one e has.
Fixture.of(Address.class).addTemplate(“brazilianAddress”, Random
new Rule() {{ A função random é utilizada para escolher um
add(“id”, 1L); valor aleatoriamente dentre uma lista de possíveis
add(“street”, “Paulista Avenue”); valores.
add(“city”, “São Paulo”);
add(“state”, “SP”);
/ 28
Listagem 4. A Listagem 4 exemplifica a codificação
da função random para geração de valores aleatórios. new SimpleDateFormat(“yyyy-MM-dd”)));
add(“contractEndingDate”, afterDate(“2011-04-15”),
new SimpleDateFormat(“yyyy-MM-dd”));
Fixture.of(Client.class).addTemplate(“geekClient”, add(“lastLoginDate”, instant(“now”));
new Rule() {{ //...
//... }});
add(“name”, random(“Nykolas Laurentino de Lima”,
“Anderson Parra”));
//...
}});
Name
As funções name auxiliam na criação de nomes
aleatórios.
Ao obter uma instância do template “geekClient”
a propriedade name terá seu valor gerado aleatoria- Listagem 7. Utilizando as funções de nomes para
mente conforme configurado. gerar nomes aleatórios.
Fixture.of(Client.class).addTemplate(“geekClient”,
Regex new Rule(){{
A função regex pode ser utilizada para gerar valo- //...
res baseados em uma expressão regex. add(“name”, firstName());
add(“lastName”, lastName());
Listagem 5. Utilizando expressões regulares para //...
gerar o valor da propriedade. }});
29 \
add(“phones”, has(3).of(Phone.class, // Client
“brazilianPhoneNumber”)); }
}}); }
}
Listagem 9. Template para Address refatorado. Após criar o TemplateLoader é possível chamar o mé-
todo “TemplateLoader.loadTemplates” para carregar
Fixture.of(Address.class).addTemplate(“brazilianAddress”, todos os templates ou carregar somente os templa-
new Rule() {{ tes desejados através do método “TemplateLoader.
add(“id”, random(Long.class, range(1L, 100L))); ClientTemplate.loadTemplates()”.
add(“street”, random(“Paulista Avenue”,
“Ibirapuera avenue”));
add(“city”, “São Paulo”);
Considerações finais
O Fixture-Factory oferece uma DSL (domain-
add(“state”, “SP”);
add(“country”, “Brazil”); -specific language) simples e intuitiva para criação
add(“zipCode”, random(“0660800”, “17720000”)); de objetos para nossos testes.
}}); Com o uso das Relation Functions, configurar os
relacionamentos entre as entidades torna-se uma
tarefa fácil. Para relacionamentos one-to-one basta
Listagem 10. Template para Phone refatorado. utilizar a função one dizendo a classe e o nome do
Fixture.of(Phone.class). template a ser utilizado. Para relacionamentos one-
addTemplate(“brazilianPhoneNumber”, -to-many a função has recebe a classe, a quantidade
new Rule() {{
de instâncias desejadas e o nome do template a ser
add(“number”, regex(“(\\d{2}) \\d{4}-\\d{4}”));
}});
utilizado.
Comparado com as Fixtures, o Fixture-Factory
Após o refactoring é possível notar a melhora no possui a vantagem de sua utilização e configuração
código, na definição dos valores que serão gerados e ser feita 100% com código Java, não precisando de ar-
o ganho que isto traz na abrangência e diversidade de quivos XML ou JSON. Com isto a leitura, debug, iden-
dados que serão testados. tificação de erros e refactoring são muito melhores
(caso você erre algo na sintaxe, o compilador vai te
Organizando seus templates avisar).
É possível criar os templates em qualquer lugar. Quando utilizamos fixtures ou criamos nossos
No @Before de uma classe de testes ou até mesmo objetos “na mão” no momento do teste, estes objetos
dentro do próprio método que realiza o teste. Entre- possuem sempre os mesmos valores fixos que foram
tanto, uma boa prática para a organização dos tem- configurados. Isto pode influenciar o programador a
plates é a criação de classes separadas para declarar escrever testes baseados nesses dados hard-coded, o
os templates de cada “módulo” do seu sistema. que pode acabar “escondendo” problemas na imple-
Nos meus projetos pessoais eu costumo criar mentação do código que poderiam ser identificados
uma classe TemplateLoader que contém uma inner no momento do teste caso os valores fossem gerados
class para cada entidade ou módulo do meu sistema. através de padrões configurados no Template do Fix-
ture-Factory. Este é um exemplo claro da vantagem
Listagem 11. Exemplo de TemplateLoader responsá- do uso de Templates e das Functions do framework
vel pela criação dos templates. para geração dos objetos.
/referências
public class TemplateLoader {
> DO repositório do Fixture-Factory no github é: https://
public static void loadTemplates() {
github.com/aparra/fixture-factory
TemplateLoader.ClientTemplate.loadTemplates();
} > Dúvidas, sugestões ou qualquer outro assunto
relacionado ao framework podem ser enviadas
private static class ClientTemplate { para a lista Mailing List(https://groups.google.com/
public static void loadTemplates() { forum/?fromgroups#!forum/fixture-factory).
Fixture.of(Client.class).addTemplate(“geekClient”,
> Fontes utilizados no artigo: https://github.com/
new Rule() {{
nykolaslima/fixture-factory-mundoj
//...
}}); > Factory-Girl, solução parecida utilizada em Ruby:
//Declaração dos outros templates relacionados a https://github.com/thoughtbot/factory_girl
/ 30