Testando Componentes e Controllers
Fazer testes de unidade com o VRaptor 4 na maioria das vezes é simples, não fugindo muito dos testes de unidade de uma classe qualquer.
Todo o controle de Injeção de Dependência é feito através do CDI e para melhorar a testabilidade de suas classes aconselhamos a injeção de dependências por construtor, dessa forma você pode trabalhar com mocks facilmente, como por exemplo:
@Controller
public class PessoaController {
private final Result result;
private final Validator validator;
/**
* @deprecated CDI eyes only
*/
protected PessoaController() {
this(null, null);
}
@Inject
public PessoaController(Result result, Validator validator) {
this.result = result;
this.validator = validator;
}
}
Para testar esse controller, podemos usar o MockResult
e MockValidator
como dependência:
public class PessoaControllerTest {
private MockResult result;
private MockValidator validator;
private PessoaController controller;
@Before
public void setUp() {
result = new MockResult();
validator = new MockValidator();
controller = new PessoaController(result, validator);
}
}
O que acontece quando fazemos a injeção de dependência via atributo, é que precisaremos do contexto do CDI e o mesmo não é suportado pelo JUnit, visto que esse cria todo um ambiente para os testes e não levanta esse contexto. No entanto há soluções para que você possa dentro do seu caso de teste subir o contexto CDI e assim usufruir da injeção de dependência, controle transacional e tudo aquilo que você precisa do CDI.
Result
e Validator
são componentes quase sempre presentes em seus Controllers, para facilitar seus testes o VRaptor fornece mocks para essas implementações.
MockResult
O MockResult
ignora os redirecionamentos que você fizer, e acumula os objetos incluídos, para você poder inspecioná-los e fazer as suas asserções.
Considere o seguinte método da classe PessoaController
:
@Post("/pessoa/adiciona")
public void adiciona(Pessoa pessoa) {
validator.addIf(pessoa.getNome() == null, new SimpleMessage("nome", "O nome deve ser preenchido"));
validator.onErrorRedirectTo(IndexController.class).index();
result.include("success", "Incluído com sucesso.");
result.redirectTo(IndexController.class).index();
}
Para testá-lo você pode em sua classe PessoaControllerTest
fazer algo como:
@Test
public void deveConterMensagemDeSucesso() {
Pessoa pessoa = new Pessoa();
pessoa.setNome("Renan Montenegro");
controller.add(pessoa);
Assert.assertTrue(result.included().containsKey("success"));
Assert.assertEquals("Incluído com sucesso.", result.included("success"));
}
Note que qualquer chamada do tipo result.use(...)
será ignorada.
MockSerializationResult
De forma bastante semelhante, você pode utilizar o MockSerializationResult
sempre que quiser inspecionar o conteúdo serializado no Result
.
Na sua classe PessoaControllerTest
o result
deve ser do tipo MockSerializationResult
, como a seguir:
private MockSerializationResult result;
Considere o seguinte método da classe PessoaController
:
@Post("/pessoa/serializa")
public void serializa(Pessoa pessoa) {
result.use(Results.json()).from(pessoa).serialize();
}
No seu teste você pode fazer algo como:
@Test
public void deveriaSerializarPessoa() {
Pessoa pessoa = new Pessoa();
pessoa.setNome("Renan Montenegro");
controller.serializa(pessoa);
Assert.assertEquals("{\"pessoa\": {\"nome\": \"Renan Montenegro\"}}", result.serializedResult());
}
MockValidator
O MockValidator
vai executar a validação acumulando possíveis erros. Para recuperá-los você pode usar o método getErrors()
como você pode ver no exemplo:
@Test
public void deveLancarValidationException() {
try {
controller.add(new Pessoa());
Assert.fail();
} catch (ValidationException e) {
List<Message> errors = e.getErrors();
Assert.assertTrue(errors.contains(new SimpleMessage("nome", "O nome deve ser preenchido")));
Assert.assertEquals(1, errors.size());
}
}
A chamada do método validator.onErrorUse
, no caso de problema de validação, irá gerar uma ValidationException
, que pode ser usado como um resultado esperado pelo seu teste, como a seguir:
@Test(expected = ValidationException.class)
public void deveLancarValidationException() {
controller.add(new Pessoa());
}