Boas Práticas para Teste Automatizados em Lumis

Objetivos

  • Apresentar conceitos básicos de testes e como utilizá-los em soluções que utilizam o Framework do Lumis Portal
  • Apresentar boas práticas e testes automatizados
  • Apresentar exemplos de utilização do LPTF para realizar Testes Unitários

Referências complementares

  • Lumis Portal Test Framework – LPTF
  • Ciclo de Vida de uma Interface Doui

Introdução

Apesar do teste manual de software ser uma técnica bastante aplicada para encontrar defeitos em uma aplicação, trata-se de um trabalho complexo e demorado. Testes manuais podem, também, falhar na busca de classes específicas de defeitos.

Automação de testes é o processo de escrita de códigos, scripts ou programas de computador com objetivo de realizar testes pré-determinados. Uma vez automatizados, um grande número de casos de teste podem ser validados rapidamente.

As vantagens da automação tornam-se mais evidentes para produtos que possuem longa vida no mercado, porque mesmo pequenas correções no código da aplicação podem causar a ‘quebra’ de funcionalidades.

A automação envolve testes de caixa-preta, em que o desenvolvedor não possui conhecimento sobre a estrutura interna do sistema (utilização de API do Lumis Portal), ou caixa-branca, em que há pleno conhecimento da estrutura interna (solução implementada que faz uso dos recursos do Lumis Portal).

Há diversos tipos de testes que podem ser utilizados, dependendo da necessidade de cada solução. Neste artigo iremos abordar Testes Unitários e Testes de Integração.

Teste Unitário

Teste unitário (ou teste de unidade) é toda a aplicação de teste nas assinaturas de entradas e saídas de um sistema que consiste em validar dados válidos e inválidos via entrada/saída. Testes deste tipo são usualmente aplicados tanto por desenvolvedores quanto por analistas de teste.

Uma unidade é a menor parte testável de um programa de computador; consideramos neste documento uma unidade como sendo um método.

Idealmente, cada teste de unidade é independente dos demais, o que possibilita ao programador testar cada método isoladamente.

Teste de Integração

Teste de integração é a fase do teste de software em que módulos são combinados e testados em grupo. Ele sucede o teste de unidade, em que os módulos são testados individualmente, e o teste de sistema, em que o sistema completo (integrado) é testado em um ambiente que simula o ambiente de produção.

O teste de integração é alimentado pelos módulos previamente testados individualmente por testes unitários, agrupando-os assim em componentes.

O propósito do teste de integração é verificar os requisitos funcionais, de desempenho e de confiabilidade na modelagem do sistema. Com este tipo de teste é possível descobrir erros de interface (interface de métodos) entre os componentes do sistema.

Utilizando Teste Unitário e Teste de Integração

Quando estamos desenvolvendo funcionalidades complexas, por exemplo as que envolvem vários cálculos, devemos ter em mente que estas são potenciais pontos de falha em um sistema, uma vez que desenvolvedores são passíveis de cometer erros.

Em cenários complexos é recomendado que, sempre que possível, funcionalidades sejam subdivididas em unidades menores, com processamentos específicos. Desta forma, teremos maior facilidade de reutilização e manutenção além de podermos realizar testes unitários em cada uma destas unidades individualmente implementadas.

Entretanto, esta abordagem não garante que a funcionalidade principal, dividida em unidades menores, não contenha erros. Logo, devemos neste caso criar um teste de integração para garantir que a funcionalidade principal (junção de todas as unidades menores) desempenhe suas funções adequadamente.

Os códigos a seguir exemplificam estas abordagens.


public class BookDataProvider {
 
	public void loadData(TabularSource<?> source) {		
		
		// Obtém a lista de livros a partir do Dao 
		List<Book> bookList = BookDaoFactory.getBookDao().listAll();
	
		// Obtém TabularData do source
		TabularData tabularData = source.getData();

		// Cria uma row para cada livro e preenche os dados 
 		for (Book book : bookList) {
			ISourceData row = tabularData.addRow();
			row.put("id", book.getId());
			row.put("isbn", book.getIsbn());
			row.put("title", book.getTitle());
			row.put("author", book.getAuthor());
		}	
 	}
}

Código 1 – Funcionalidade Ler livros do Banco de dados original


public class BookDataProvider {

	public void loadData(TabularSource<?> source) {		
		
		// Obtém a lista de livros a partir do Dao 
		List<Book> bookList = obtainBookData();
		
		// Obtém TabularData do source
		TabularData tabularData = source.getData();

		// Cria uma row para cada livro e preenche os dados 
		fillTabularData(tabularData, bookList);
	}
	
	/**
	 * Obtain book data.
	 * @return	a list of Book.
	 */
	protected List<Book> obtainBookData(){
		List<Book> bookList = BookDaoFactory.getBookDao().listAll();
		return bookList;
	}
	
	/**
	 * Fill the tabular data with the book data.
	 * @param source	 the source.		
        * @param booklist the book list.		
	 */
	protected void fillTabularData(TabularData tabularData, 
						List<Book> bookList) {
		for (Book book : bookList) {
			ISourceData row = tabularData.addRow();
			row.put("id", book.getId());
			row.put("isbn", book.getIsbn());
			row.put("title", book.getTitle());
			row.put("author", book.getAuthor());
		}		
	}
}

Código 2 – Funcionalidade Ler livros do Banco de dados reestruturada

A reestruturação da funcionalidade “Ler Livros do Banco de Dados”, apresentada no Código 2, resume-se em criar novos métodos para realizar atividade específicas como, por exemplo, obter as informações do banco de dados (linha 6) e preencher um tabular data (linha 12).

Como mencionado no início da seção, esta abordagem nos possibilita testar individualmente estas duas etapas: a leitura das informações do banco de dados e o preenchimento do tabular data do DataProvider.

A funcionalidade apresentada como exemplo pode nos parecer muito simples, mas mesmo assim é recomendada a abordagem de reestruturação.

Neste exemplo podemos utilizar a API JUnit tanto para realizar testes unitários (testando cada método criado) quanto para realizar testes integrados (funcionamento da funcionalidade como um todo).

Testes de Soluções no Lumis Portal

Nesta seção serão apresentados pontos relacionados a testes unitários para soluções desenvolvidas em Lumis Portal.

Dependências entre a implementação da solução e o Framework do Lumis Portal

Ao desenvolver uma solução utilizando o Lumis Portal, é importante elaborar testes unitários para validar cada implementação.

Se uma implementação não faz uso do Framework do Lumis Portal, podemos utilizar as técnicas de construção de testes unitários disponíveis no mercado. Entretanto, se a solução fizer uso do Framework do Lumis Portal, como por exemplo, utilização da API de conexão com a base de dados do Lumis, é necessário realizar algumas configurações prévias para que os testes possam ser executados corretamente.

Exemplo de Teste Unitário no Lumis Portal

O Código 3 apresenta um exemplo de teste unitário de uma solução que possui dependência com o Framework do Lumis Portal.


public class ExemploJUnit{   
  
    public int count(){   
        Long totalRows = (Long) ManagerFactory.getEntityManager()   
        .createQuery("select count(*) from EntityMaped e")   
        .getSingleResult();    
        return totalRows.intValue();   
    }   
  
}

Código 3 – Teste Unitário com dependência do Framework do Lumis Portal

A dependência neste código está localizada na linha 4 na chamada ao “ManagerFactory”.

Quando é realizada uma chamada para o “ManagerFactory” antes da infraestrutura do portal ter sido inicializada teremos um erro de execução do teste, pois informações referentes ao contexto de execução não foram inicializadas.

Quando é criada uma transação via API do Lumis Portal, esta inicializa a infraestrutura do portal evitando um erro na execução. Contudo, nem sempre é necessário que sejam criadas transações para execução de determinados testes. É preciso criar uma configuração local ao projeto de teste, informando o path de instalação do Lumis, com o qual o projeto de teste será capaz de resolver as referências para as classes do Lumis Portal Framework.

A configuração mencionada cria um arquivo de propriedades chamado “PortalConfiguration.properties” no pacote “lumis.portal” do projeto de teste. O Código 4 apresenta o conteúdo deste arquivo de propriedades.


	lumisDataPath=path/to/lumisdata   
	developmentMode=true  

Código 4 – Arquivo de Propriedades

O arquivo de propriedades contém duas informações: lumisDataPath e developmentMode. O atributo “lumisDataPath” deve conter o caminho para a pasta “lumisdata” da instalação do Lumis, e o Atributo “developmentMode=true” permite que o ambiente de teste execute sem ter de parar o servidor de aplicação local.

É importante lembrar que as informações da memória não serão sincronizadas entre a execução do ambiente de teste e o servidor de aplicação. Este ponto seria um problema se o teste tivesse que acessar alguma informação no servidor de aplicação local que dependesse de alterações realizadas pelos testes.

Lumis Portal Test Framework – LPTF

O LPTF é um framework desenvolvido para realizar testes integrados automatizados em componentes do Lumis tais como instâncias de interface, canais, páginas, objetos request e response, etc. Este framework está disponível a partir da versão 5.6.0 do Lumis Portal.

Para maiores detalhes sobre o LPTF consulte o artigo “Lumis Portal Test Framework” disponível na base de conhecimento Java.

Exemplos de Testes em Soluções que Usam o Framework do Lumis Portal

Nesta seção serão apresentados alguns exemplos de testes que podem ser utilizados em soluções que utilizam o framework do Lumis Portal.

Os exemplos aqui apresentados podem parecer muito simples, mas o intuito é apenas o de ilustrar a confecção de testes, cuja complexidade pode variar de solução para solução. Além disso, é possível que em algumas situações existam diferentes possibilidades para realizar o mesmo teste.

Todos os exemplos apresentados nesta seção possuem dependência com o framework do Lumis Portal. Para seu perfeito entendimento é recomendada a leitura do artigo “Lumis Portal Test Framework - LPTF”.

Para todos os exemplos a seguir foi utilizado um mesmo serviço, apresentado nos códigos 5 e 6.


<?xml version="1.0" encoding="UTF-8"?>
<serviceDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.lumis.com.br/lumisportal/xsd/servicedefinition.xsd">

	<service id="lumis.test.doui.sample" name="STR_SERVICE_NAME" type="lum_doui">
		<description>STR_SERVICE_DESCRIPTION</description>
	</service>
	
	<interfaces>
		<interface id="list" name="STR_LIST" type="lum_douiList" />
		<interface id="processAction" name="STR_LIST" type="lum_doui" />
	</interfaces>

</serviceDefinition>

Código 5 – Service Definition


<?xml version="1.0" encoding="UTF-8"?>
<doui:douiDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:doui="http://www.lumis.com.br/lumisportal/xsd/doui" xmlns:control="http://www.lumis.com.br/douicontrols">
	<service id="lumis.test.doui.sample">
		<sources>
			<source id="default" type="table">
				<table>lum_News</table>
				<fields>
					<field id="id" display="false" name="STR_ID" dataType="string" isPrimaryKey="true"/>
					<field id="title" name="STR_TITLE" dataType="string" isPrimaryName="true" isSearchable="true"/>
				</fields>
			</source>
		</sources>
	</service>
	<interfaces>
		<interface id="list">
			<sources>
				<source id="default" readData="always">
					<fields inherit="all"/>
				</source>
			</sources>
			<controls>
				<control:lum_form>
					<control:lum_text text="test render" />
					<control:lum_tabularData id="lita" sourceId="default" />
				</control:lum_form>
			</controls>
		</interface>
		<interface id="processAction">
			<sources>
				<source id="default" readData="always">
					<fields inherit="all"/>
				</source>
			</sources>
			<controls>
				<control:lum_form>
					<control:lum_inputText id="text" defaultValue="test render" />
					<control:lum_tabularData id="lita" sourceId="default" />
				</control:lum_form>
			</controls>
			<processActions>
				<processAction id="commit" className="lumis.test.sample.SampleListProcessActionHandler">
					<response type="doui_standardCommit" />
				</processAction>
			</processActions>
		</interface>
	</interfaces>
</doui:douiDefinition>

Código 6 – Doui Definition

O serviço possui duas interfaces simples que fazem uso de um mesmo source. Como o objetivo aqui é apresentar uma abordagem para testes, o serviço contém apenas o necessário para a demonstração.

Como Testar o Render de uma Interface

Este exemplo apresenta uma forma de testar uma interface de serviço desenvolvida em uma solução. A interface testada será a “list”.

No Código 7, a seguir, são definidos alguns atributos necessários pelo LPTF. Nos métodos “setUp” e “tearDown” os objetos são inicializados e liberados, respectivamente.


public class TestSample
{
	protected IRenderRequestCycle renderRequestCycle;

	protected StructureHelper structureHelper;

	protected ServiceInterfaceInstanceConfig serviceInterfaceInstanceConfig;

	protected ITransaction transaction;

	protected SessionConfig sessionConfig;

	@Before
	public void setUp() throws PortalException
	{
		// cria e inicia a transação:
		this.transaction = PortalTransactionFactory.createTransaction();
		this.transaction.begin();

		// inicia a sessão
		this.sessionConfig = ManagerFactory.getAuthenticationManager().impersonate(UserConfig.USER_SYSTEM_ID);

		// cria a instância de StructureHelper:
		this.structureHelper = new StructureHelper();

		// utilizando StructureHelper, cria instância da interface de serviço:
		this.serviceInterfaceInstanceConfig = structureHelper.createServiceInterfaceInstance("lumis.test.doui.sample", "list");

		// obtém implementações de IRenderRequestCycle e IActionRequestCycle
		// através da RequestCycleFactory
		RequestCycleFactory requestCycleFactory = new RequestCycleFactory();
		this.renderRequestCycle = requestCycleFactory.createRenderRequestCycle(this.serviceInterfaceInstanceConfig);
	}
	
	@After
	public void tearDown() throws PortalException
	{
		try
		{
			// libera a transação
			this.transaction.dispose();

			// finaliza a sessão
			ManagerFactory.getAuthenticationManager().endImpersonation(this.sessionConfig);
		}
		finally
		{
			// chama o método cleanup
			this.structureHelper.cleanup();
		}
	}

	@Test
	public void testRender() throws Exception
	{
		// conteúdo que deve conter na interface
		String contentHtml = "test render";
		
		this.transaction.commit();
		
		// chama o método render da interface
		this.renderRequestCycle.render();
		
		// efetua os asserts
		assertTrue(this.renderRequestCycle.getResponse().getWriterOutput().contains(contentHtml));			
	}
}

Código 7 – Teste de Interface

O método “testRender” é responsável por testar a renderização da interface. Seu objetivo é que, após a renderização da interface (linha 62), verifiquemos se o conteúdo produzido é o esperado (linha 65).

No exemplo, verificamos se o conteúdo produzido contém o valor “test render”, um texto definido no douidefinition da interface (Código 6, linha 36).

Como Testar o ProcessAction de uma Interface

Este exemplo apresenta uma forma de se testar a execução de um “processAction” de uma interface. É importante destacar que o intuito deste teste é verificar se o “processAction” da interface está sendo executado corretamente.


public class TestSample
{
	protected IActionRequestCycle actionRequestCycle;

	protected StructureHelper structureHelper;

	protected ServiceInterfaceInstanceConfig serviceInterfaceInstanceConfig;

	protected ITransaction transaction;

	protected SessionConfig sessionConfig;

	@Before
	public void setUp() throws PortalException
	{
		// cria e inicia a transação:
		this.transaction = PortalTransactionFactory.createTransaction();
		this.transaction.begin();

		// inicia a sessão
		this.sessionConfig = ManagerFactory.getAuthenticationManager().impersonate(UserConfig.USER_SYSTEM_ID);

		// cria a instância de StructureHelper:
		this.structureHelper = new StructureHelper();

		// utilizando StructureHelper, cria instância da interface de serviço:
		this.serviceInterfaceInstanceConfig = structureHelper.createServiceInterfaceInstance("lumis.test.doui.sample", "processAction");
		// obtém implementações de IRenderRequestCycle e IActionRequestCycle
		// através da RequestCycleFactory
		RequestCycleFactory requestCycleFactory = new RequestCycleFactory();
		this.actionRequestCycle = requestCycleFactory.createActionRequestCycle(this.serviceInterfaceInstanceConfig);
		// define o nome do processAction da interface
		actionRequestCycle.getRequest().setParameter("doui_processActionId", "commit");
	}
	
	@After
	public void tearDown() throws PortalException
	{
		try
		{
			// libera a transação
			this.transaction.dispose();

			// finaliza a sessão
			ManagerFactory.getAuthenticationManager().endImpersonation(this.sessionConfig);
		}
		finally
		{
			// chama o método cleanup
			this.structureHelper.cleanup();
		}
	}

	@Test
	public void testProcessAction() throws Exception
	{
		this.transaction.commit();
		
		// executa o processAction da interface:
		this.actionRequestCycle.processAction();
		assertTrue(this.actionRequestCycle.getResponse().getRenderParameterMap().get("fail") == null);

		SampleListProcessActionHandler.fail = true;
		
		// executa o processAction da interface:
		this.actionRequestCycle.processAction();
		assertTrue(this.actionRequestCycle.getResponse().getRenderParameterMap().get("fail") != null);
	}
}

Código 8 – Teste de processAction

O método “testProcessAction” é responsável por testar a chamada para o “processAction” da interface. O objetivo é disparar uma execução do “processAction” e, em seguida, verificar se o mesmo adicionou o parâmetro “fail” no “response”, o que só ocorre se o atributo estático “fail” for “true”.

Na linha 63 é atribuído o valor “true” a este atributo para verificar se o “processAction” irá comportar-se da forma esperada. Note que, neste ponto, poderíamos utilizar diferentes abordagens para realizar o mesmo teste de execução do “processAction” como, por exemplo, adicionar algum parâmetro no “request” como se o mesmo viesse da interface.

Como Testar um DataProvider

Neste exemplo temos um “dataProvider” BookDataProvider (Código 9) que tem por objetivo consultar a lista de livros na base de dados e, em seguida, popular o source com as informações coletadas.


public class BookDataProvider implements IDataProvider<TabularSource<?>> {

	public void loadData(SessionConfig sessionConfig, 
						TabularSource<?> source, 
						ITransaction transaction)
					throws PortalException {
		
		// Obtém a lista de livros a partir do Dao 
		List<Book> bookList = obtainBookData();
		
		// Obtém TabularData do source
		TabularData tabularData = source.getData();

		// Cria uma row para cada livro e preenche os dados 
		fillTabularData(tabularData, bookList);
	}
	
	/**
	 * Obtain book data.
	 * @return	a list of Book.
	 */
	protected List<Book> obtainBookData() throws PortalException {
		List<Book> bookList = BookDaoFactory.getBookDao().listAll();
		return bookList;
	}
	
	/**
	 * Fill the tabular data with the book data.
	 * @param source	 the source.		
 * @param booklist the book list.		
	 */
	protected void fillTabularData(TabularData tabularData, 
						List<Book> bookList)
					throws PortalException {
		for (Book book : bookList) {
			ISourceData row = tabularData.addRow();
			row.put("id", book.getId());
			row.put("isbn", book.getIsbn());
			row.put("title", book.getTitle());
			row.put("author", book.getAuthor());
		}		
	}
}

Código 9 – DataProvider

O teste apresentado no Código 10, a seguir, realiza testes em cada um dos métodos pertencentes ao “dataProvider” com o intuito de verificar o comportamento de cada um deles. Na próxima seção será apresentada uma forma de testar um source de uma interface.


public class TestBookDataProvider {
	
	@Test
	public void testFillTabularData() throws PortalException {
		// Cria um livro
		Book book = new Book();
		book.setId("1");
		book.setTitle("JUnit in Action");
		book.setAuthor("Vincent Massol");
		book.setIsbn("1930330995");
		
		// Adiciona o livro a uma lista de livros
		List<Book> bookList = new ArrayList<Book>();
		bookList.add(book);
		
		// Cria um TabularData e chama o fillTabularData
		BookDataProvider dataProvider = new BookDataProvider();
		TabularData tabularData = new TabularData();
		dataProvider.fillTabularData(tabularData, bookList);
		
		// Confere o resultado
		assertEquals(1, tabularData.size());
		ISourceData row = tabularData.getRows().get(0);
		assertEquals("1", row.get("id"));
		assertEquals("JUnit in Action", row.get("title"));
		assertEquals("Vincent Massol", row.get("author"));
		assertEquals("1930330995", row.get("isbn"));
	}		
}

Código 10 – Teste de DataProvider

Como Testar um Source

Neste exemplo, ao contrário do apresentado anteriormente, será testado o carregamento do source da interface “processAction”.


public class TestSample
{
	
	protected IDouiRenderRequestCycle douiRenderRequestCycle;

	protected StructureHelper structureHelper;

	protected ServiceInterfaceInstanceConfig serviceInterfaceInstanceConfig;

	protected ITransaction transaction;

	protected SessionConfig sessionConfig;

	@Before
	public void setUp() throws PortalException
	{
		// cria e inicia a transação:
		this.transaction = PortalTransactionFactory.createTransaction();
		this.transaction.begin();

		// inicia a sessão
		this.sessionConfig = ManagerFactory.getAuthenticationManager().impersonate(UserConfig.USER_SYSTEM_ID);

		// cria a instância de StructureHelper:
		this.structureHelper = new StructureHelper();

		// utilizando StructureHelper, cria instância da interface de serviço:
		this.serviceInterfaceInstanceConfig = structureHelper.createServiceInterfaceInstance("lumis.test.doui.sample", "processAction");
		DouiRequestCycleFactory douiRequestCycleFactory = new DouiRequestCycleFactory();
		douiRenderRequestCycle = douiRequestCycleFactory.createRenderRequestCycle(serviceInterfaceInstanceConfig);
		
	}
	
	@After
	public void tearDown() throws PortalException
	{
		try
		{
			// libera a transação
			this.transaction.dispose();

			// finaliza a sessão
			ManagerFactory.getAuthenticationManager().endImpersonation(this.sessionConfig);
		}
		finally
		{
			// chama o método cleanup
			this.structureHelper.cleanup();
		}
	}
	@Test
	public void testSource() throws Exception
	{
		//Criar massa de dados no banco de dados para o teste aqui.
	
		douiRenderRequestCycle.executeUntilLoadSources();
		assertTrue(!douiRenderRequestCycle.getDouiContext().getSourceContainer().getSourceById("default").getData().isEmpty());

		//Apagar massa de dados criada no banco de dados para o teste aqui.
	}
}

Código 11 – Teste de Source

De acordo com o Código 11, o método “testSource” é o responsável por realizar o carregamento do source (linha 56). O método “executeUntilLoadSource” realizará todas as etapas de inicialização de uma interface até a conclusão do carregamento dos sources.

Após esse passo, é realizada a verificação se o source está vazio ou não. Como aqui temos acesso ao source em si, poderíamos realizar diferentes testes para atender a diferentes objetivos.

Contudo, é importante ressaltar que neste exemplo foram omitidos os passos de popular a base de dados com dados para testes e ao final limpar a base de dados com os dados criados. Logo, estamos assumindo que, em cenários reais, o desenvolvedor realizará estes passos.

Como Testar um ProcessActionHandler

Este exemplo apresenta uma abordagem para testar um “processAction” isoladamente da interface. O objetivo aqui é verificar o comportamento do “processAction”. Para isso, o Código 12 apresenta a implementação do “processAction” e o Código 13, seu teste.


public class ExemploJUnitProcessAction extends ProcessActionHandler> {

	private boolean situation;
	
	public void processAction() throws PortalException {
		verify(getSituation());
	}

	public void setSituation(boolean situation){
		this.situation = situation;
	}
	public boolean getSituation(){
		return this.situation;	
	}
	public void verify(boolean b) throws PortalException{
		if(b){
			throw new PortalException("Exceção");
		}else{
			return;		
		}
	}
}

Código 12 – ProcessAction teste

O código 13, a seguir, é bem simples.

No método “setUp” é criada uma instância do “processAction” e, em seguida, o método “testProcessAction” executa o “processAction” em si (linha 13). Como apresentado no exemplo de teste de um “dataProvider”, poderiam ser realizados outros testes a métodos que poderiam pertencer ao “processAction”.


public class ExemploJUnitProcessActionTest extends TestCase {
	ExemploJUnitProcessAction e = new ExemploJUnitProcessAction();

	@Override
	protected void setUp() throws Exception {
		e.setSituation(false);	
//aqui será modificado o resultado do teste. para ok, mude para "true".
	}

	public void testProcessAction(){
		try
		{
		  e.processAction();
		  assertEquals(true,false);//forçamos o teste ser falso.						  
		}catch(PortalException p){
		  assertEquals(true,true);
		}	
	}
}

Código 13 – Teste do ProcessAction

Como Testar um Controle

Neste exemplo será apresentado um teste de um controle “inputText” definido na interface “processAction”.

O código a seguir testa o valor do controle após a leitura do “request”. Na linha 5 é disparada a ação para simular o ciclo de vida de uma requisição até o ponto de leitura das informações do “request”.

Como conhecemos previamente o tipo do controle que estamos testando, é necessário fazer um “cast” para o tipo apropriado durante sua recuperação do “controlContainer”. Após isso, basta realizar as comparações.


@Test
	public void testControl() throws Exception
	{
		// Executa o ciclo de vida até o ponto de leitura das informações do request
		douiRenderRequestCycle.executeUntilLoadFromRequest();
		//Obtem o valor do controle após ler o request.
		InputTextControl control = (InputTextControl) douiRenderRequestCycle.getDouiContext().getControlContainer().getControlById("text");
		String value = control.getValue(String.class);
		//valida o valor
		assertTrue("test render".equalsIgnoreCase(value));

		// Executa o ciclo de vida até o ponto de renderizacao dos controles
		douiRenderRequestCycle.executeUntilRenderData();
		//Obtem o xml produzido pelo renderData do controle.
		String renderData = douiRenderRequestCycle.getDouiContext().getControlContainer().getControlById("text").getRenderData();
		//valida o xml produzido
		String expected_result = "<control defaultValue=\"test render\" id=\"text\" trim=\"true\" type=\"lum_inputText\"/>";
		assertTrue(expected_result.equalsIgnoreCase(renderData));
	}

Código 14 – Teste de Controle

A segunda parte do teste é feita sobre o XML produzido pelo controle. Neste caso é necessário disparar a ação referente ao ciclo de vida que prepara o controle (linha 13). Após este ponto, é possível obter o XML produzido pelo controle e verificar se o mesmo está conforme o esperado.

O ponto a se destacar neste teste é que não precisamos realizar o ciclo de vida completo de uma requisição para testar uma informação de um controle. Para maiores informações sobre o ciclo de vida de uma interface Doui, consulte a base de conhecimento.

Como Testar um Clock

Este último exemplo testa um “clock” de um serviço. O “clock” em questão realiza apenas uma contagem de quantas vezes ele foi executado. Logo, o teste a seguir cria os objetos necessários para a chamada do método “doTick” do “clock”. Neste exemplo é criado um “ClockConfig” e, nele, configurado o id do serviço.


@Test
	public void testClock() throws Exception
	{
		ClockConfig clockConfig = new ClockConfig();
		clockConfig.setServiceId("lumis.test.doui.sample");
	
		SampleClock clock = new SampleClock();
		
		clock.doTick(sessionConfig, clockConfig);
		clock.doTick(sessionConfig, clockConfig);
		clock.doTick(sessionConfig, clockConfig);

		assertTrue(clock.count == 3);

	}

Código 15 – Teste de Clock

É importante lembrar que este teste de “clock” é muito simples, mas em cenários reais, podemos nos deparar com situações mais complexas cabendo ao desenvolvedor avaliar a melhor estratégia para realizar o teste do “clock”.

Autor: André Santos