Enlaces e información
Comenta lo que creas oportuno.
- Otros posts
- Testeando el Interfaz.
- Organización
Preparación de un interfaz para testeo unitario
Voy a exponer en este post un método que nos va a permitir realizar testeos unitarios sobre un formulario. Siempre ha sido la labor más complicada: realizar un testeo contra el interfaz de usuarios. Este sistema aquí descrito es una manera de programar un interfaz mediante el patrón Model-View-Controller, lo cual nos va a permitir programar testeos automatizados.
Lo primero será diseñar como va a ser el formulario a testear (propongo un ejemplo muy básico: una calculadora):

Es muy simple, pero de él podemos obtener los elementos a mostrar, o los datos:
- Operador1 (Double)
- Operador2
- Operación (Integer: 0- Suma, 1- Resta. 2- Multiplicación, 3- Division)
- Resultado (Double)
También se pueden obtener las operaciones, en este caso, solo una:
- Calcular
A partir de aqui, podemos definir dos Interfaces, uno encargado de los datos (ICalculadoraView) y otro de las operaciones (ICalculadoraController):
public interface ICalculadoraView
{
double Operador1 {get; set;}
double Operador2 {get; set;}
double Resultado {get; set;}
eOperacion Operacion {get; set;}
}public interface ICalculadoraController
{
void Calcular();
}
Bien, definimos dos variables dentro del formulario:
private ICalculadoraView m_objView;
private ICalculadoraController m_objController;
Y ya podemos realizar la operación del formulario (Calcular) al pulsar el botón del formulario, chequeando primero que los datos son válidos:
private void cmdCalcular_Click
(object sender,
System.EventArgs e)
{
// Chequear la validez de los datos
if (txtOperador1.Text.Length == 0)
{
MessageBox.Show(
“Debe introducir un valor en el primer operador”);
return;
}
if (txtOperador2.Text.Length == 0)
{
MessageBox.Show(
“Debe introducir un valor en el segundo operador”);
return;
}// Llamar al controlador
m_objController.Calcular();
}
Esto es así de sencillo gracias a que la vista (el objeto de tipo ICalculadoraView) es el encargado de mapear los controles de pantalla con los datos a utilizar por el controlador:
// Clase del manejo de la vista para un formulario
// WinForm
public class CCalculadoraView
: ICalculadoraView
{
// Objetos del formulario asociados a la vista
protected TextBox m_txtOperador1;
protected TextBox m_txtOperador2;
protected TextBox m_txtResultado;
protected RadioButton m_chkSuma;
protected RadioButton m_chkResta;
protected RadioButton m_chkMultiplicacion;
protected RadioButton m_chkDivision;// Constructor
public CCalculadoraView(
TextBox txtOperador1,
TextBox txtOperador2,
TextBox txtResultado,
RadioButton chkSuma,
RadioButton chkResta,
RadioButton chkMultiplicacion,
RadioButton chkDivision)
{
m_txtOperador1 = txtOperador1;
m_txtOperador2 = txtOperador2;
m_txtResultado = txtResultado;
m_chkSuma = chkSuma;
m_chkResta = chkResta;
m_chkMultiplicacion = chkMultiplicacion;
m_chkDivision = chkDivision;
}// Implemetacion del interfaz
public double Operador1
{
get {return Convert.ToDouble(m_txtOperador1.Text);}
set {m_txtOperador1.Text = value.ToString(); }
}
public double Operador2
{
get {return Convert.ToDouble(m_txtOperador2.Text);}
set {m_txtOperador2.Text = value.ToString(); }
}
public double Resultado
{
get {return Convert.ToDouble(m_txtResultado.Text);}
set {m_txtResultado.Text = value.ToString(); }
}
public eOperacion Operacion
{
get
{
if (m_chkDivision.Checked == true)
return eOperacion.eDivision;
if (m_chkMultiplicacion.Checked == true)
return eOperacion.eDivision;
if (m_chkResta.Checked == true)
return eOperacion.eResta;return eOperacion.eSuma;
}
set
{
switch(value)
{
case eOperacion.eSuma:
m_chkSuma.Checked = true;
break;
case eOperacion.eResta:
m_chkResta.Checked = true;
break;
case eOperacion.eMultiplicacion:
m_chkMultiplicacion.Checked = true;
break;
case eOperacion.eDivision:
m_chkDivision.Checked = true;
break;
}
}
}
}
Y el controlador (ICacluladoraController) solo ve los datos del formulario como datos genericos proporcionados por la vista (ICalculadoraView):
// Implementacion del controlador del formulario
public class CCalculadoraController
: ICalculadoraController
{
protected ICalculadoraView m_objView;public CCalculadoraController(
ICalculadoraView objView)
{
m_objView = objView;
}// Implementacion del metodo Calcular
public void Calcular()
{
switch(m_objView.Operacion)
{
case eOperacion.eSuma:
m_objView.Resultado =
m_objView.Operador1 +
m_objView.Operador2;
break;
case eOperacion.eResta:
m_objView.Resultado =
m_objView.Operador1 -
m_objView.Operador2;
break;
case eOperacion.eMultiplicacion:
m_objView.Resultado =
m_objView.Operador1 *
m_objView.Operador2;
break;
case eOperacion.eDivision:
m_objView.Resultado =
m_objView.Operador1 /
m_objView.Operador2;
break;
}
}
}
Ya solo falta crear los objetos dentro del formulario, en el constructor de dicho formulario, y pasarle la vista (ICalculadoraView) al controlador (ICalculadoraView):
// Crear la implementacion de la vista:
m_objView = new CCalculadoraView (
txtOperador1,
txtOperador2,
txtResultado,
chkSuma,
chkResta,
chkMultiplicacion,
chkDivision);// Crear la implementacion del control, pasandole
// la vista
m_objController = new CCalculadoraController(
m_objView);
Parece todo muy complicado… no? Bueno, en principio si, pero hemos conseguido varias cosas que van a mejorar mucho el desarrollo del proyecto:
- Un interfaz de usuario muy fino. Cuanta menos lógica de negocio haya en el GUI mucho mejor.
- El “mapeador” de controles de usuario a datos (ICalculadoraView en este ejemplo) es universal en el sentido de que se puede utilizar para cualquier interface gráfico que se defina (WebForms, WinForms, etc).
- Al separar (mediante el ICalculadorView) los datos de la interfaz, el controlador (ICalculadoraController) es el mismo para cualquier interfaz gráfico que se defina, por lo que basta con testear los métodos públicos del controlador para testear el funcionamiento de la aplicación de cara al usuario.
[…] Preparación de un interfaz para testeo unitario […]