Posts Tagged 'teste'

Testando sua interface em Swing

A prática de escrever testes automatizados vem sendo amplamente adotada por equipes de todo o mundo. Embora a maior parte do material encontrado na internet trata sobre testes unitários, também é possível escrever testes de integração automatizados, testes do banco de dados, etc. Enfim, é possível automatizar qualquer tipo de teste, uma vez que a variedade de ferramentas para este propósito é grande.
Nesse post, eu quero mostrar um exemplo simples de como é possível escrever um teste automatizado para uma interface em Swing, usando apenas o framework JUnit. O nosso exemplo será uma simples calculadora, que realiza apenas a soma, para resumir o código, vejamos:

public class TestCalculadora {
	@Test
	public void testSomar() {
		Calculadora calculadora = new Calculadora();
		
		Integer numero1 = 10;
		Integer numero2 = 5;
		
		calculadora.textFieldNumero1.setText(numero1.toString());
		calculadora.textFieldNumero2.setText(numero2.toString());
		
		calculadora.buttonSomar.doClick(); //simula um click programaticamente
		
		Integer resultado = numero1 + numero2;
		
		Assert.assertEquals(resultado.toString(), calculadora.textFieldResultado.getText());
	}
}

O teste acima especifica que nossa calculadora deve receber os números a serem somados em campos de texto, e após clicar no botão de soma, o resultado será exibido em um terceiro campo de texto. Reparem, que o método doClick() simula programaticamente o click no botão.
A implementação de Calculadora é o código suficiente para passar nesse primeiro teste:

public class Calculadora {
	JTextField	textFieldResultado;
	JTextField	textFieldNumero1;
	JTextField	textFieldNumero2;
	JButton		buttonSomar;

	public Calculadora() {
		this.textFieldResultado = new JTextField();
		this.textFieldNumero1 = new JTextField();
		this.textFieldNumero2 = new JTextField();
		this.buttonSomar = new JButton();
		
		this.buttonSomar.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				somar();
			}
		});
	}
	
	private void somar(){
		int numero1 = Integer.valueOf(textFieldNumero1.getText());
		int numero2 = Integer.valueOf(textFieldNumero2.getText());
		
		textFieldResultado.setText(String.valueOf((numero1 + numero2)));
	}
}

Como podem reparar, esse classe não é uma interface gráfica propriamente dita, pois não estende nenhum componente gráfico. Mas isso é resolvido facilmente:

public class Calculadora extends JFrame {
	JTextField	textFieldResultado;
	JTextField	textFieldNumero1;
	JTextField	textFieldNumero2;
	JButton		buttonSomar;

	public Calculadora() {
		this.setSize(150, 200);
		this.textFieldResultado = new JTextField(12);
		this.textFieldResultado.setEnabled(false);
		this.textFieldNumero1 = new JTextField(12);
		this.textFieldNumero2 = new JTextField(12);
		this.buttonSomar = new JButton("Somar");

		this.buttonSomar.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				somar();
			}
		});

		getContentPane().setLayout(new BorderLayout());

		JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER));

		panel.add(textFieldNumero1);
		panel.add(textFieldNumero2);
		panel.add(buttonSomar);
		panel.add(textFieldResultado);

		getContentPane().add(panel, BorderLayout.CENTER);
	}

	private void somar() {
		int numero1 = Integer.valueOf(textFieldNumero1.getText());
		int numero2 = Integer.valueOf(textFieldNumero2.getText());

		textFieldResultado.setText(String.valueOf((numero1 + numero2)));
	}

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			@Override
			public void run() {
				Calculadora calculadora = new Calculadora();
				calculadora.setVisible(true);
			}
		});
	}
}

Assim, com o teste testSoma() passando, a funcionalidade da tela está pronta, restando adicionar o código relativo à aparência propriamente dito. Percebemos, que o teste automatizado não substitui um teste manual, afinal de contas, requisitos como layout, estética da tela, usabilidade e etc. dependem da percepção do usuário. Porém, auxilia bastante no desenvolvimento das funcionalidades da tela. A desvantagem nesse caso, é a necessidade de expor os componentes da tela para a classe de teste. Nesse caso, coloquei a interface e o teste no mesmo pacote e declarei os componentes da tela com acesso default. As alternativas para manter estes campos private seria criar getters para os componentes, criar métodos que delegam o set das propriedades, ou ainda, acessar os campos por reflection.


Categorias

Atualizações Twitter