Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Esta es la segunda entrada de la serie dedicada a pruebas unitarias. Si en la primera vimos una introducción a la programación guiada por pruebas, en esta segunda vamos a empezar a revisar los frameworks disponibles que nos ayudan a realizar los test unitarios.
Para realizar Test unitarios con Delphi disponemos de dos frameworks; Según la versión de Delphi podemos utilizarlos indistintamente, aunque a partir de la versión XE8 de Delphi, se recomienda utilizar DUnitX.
CREACIÓN DE PRUEBAS UNITARIAS (FRAMEWORKS)
Para realizar test unitarios con Delphi podemos utilizar los frameworks (ambos Open Source) DUnit y DUnitX.
A partir de la versión Delphi XE8 Embarcadero recomienda utilizar DUnitX, ya que DUnit ha quedado desactualizado. Si se ha trabajado con DUnit es relativamente fácil migrar los test ya existentes a DUnitX.
Lo que vamos a hacer es realizar los test con ambos paquetes y de esta forma también podremos ver las diferencias entre ambos y las ventajas prácticas que nos pueden aportar.
FRAMEWORK DUNIT
Para crear nuestro proyecto de pruebas unitarias que testee la clase TAritmeticaBasica de nuestra unit UClass.TAritmeticaBasica, podemos utilizar el asistente que ya trae el paquete. Si en nuestra versión de delphi no está instalado este paquete (DUnit), hay que descargarlo (de la dirección que hay más arriba) e instalarlo.
Lo primero es crear un proyecto que utilice nuestra Unit. Sería nuestra aplicación que va a utilizar esta unit. Para ello crearemos un nuevo proyecto llamado PAritmeticaBasica y le añadiremos la unit anterior.
A continuación vamos a generar, utilizando el asistente, el proyecto para las pruebas unitarias (y lo añadiremos al mismo grupo de proyectos). De esta forma tendremos nuestro proyecto y junto a el el proyecto de pruebas.
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Bueno, si no te has enterado, ya llegas tarde. ;-D (aunque tienes otra oportunidad).
La semana pasada del 5 al 9 de Septiembre se han realizado las 5 sesiones online gratuitas de 2 horas cada una, sobre la última versión de Delphi (15:00 y 20:00 hora española).
Desde la propia página del Boot Camp donde estaba toda la información, tienes ahora acceso al replay de todas las sesiones realizadas.
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Para complementar la entrada anterior (Hablando del tiempo… (OpenWeatherMap) 1/2) y “acabarla” me queda publicar el desarrollo móvil correspondiente a la aplicación que vimos anteriormente.
Como ya os comenté en la entrada anterior, el código a utilizar es prácticamente el mismo que hemos utilizado en las aplicaciones para windows (VCL). La mayor diferencia que me he encontrado en el tratamiento de la respuesta JSON que obtenemos del servidor.
Para versiones antiguas de Delphi, podéis utilizar si lo necesitáis la misma librería que ya he recomendado aquí otras veces. Se trata de lkJSON que podéis encontrar en Sourceforge.
En las nuevas versiones de Delphi ya está disponible la unit System.JSON, con lo necesario para no utilizar librerías externas.
function TForm1.ParseTiempoCiudadesHist(AObjResp: TlkJSONobject;var ATiempoProxHoras: TTiempoProxHoras):Boolean;var
i, j, num, index:integer;
oHorasList, OWList:TlkJSONlist;
oHora, oCoord, oMain, oWind, oWeather:TlkJSONobject;
Str:String;begin// ini
Result :=False;// Si no está asignado salimos..ifnotAssigned(AobjResp)thenbegin
Exit;end;// Si hay error no parseamosif IsErrorResponse(AObjResp, errCode, ErrMsg)thenbegin
Exit;end;// proteccion para el parseotry// cod. devuelto (datos principales
ATiempoProxHoras.Cod:= errCode;
num := AObjResp.IndexOfName('count');if(num <>-1)thenbegin
num := GetAsInteger(AObjResp.Field['count'].Value);end;// si no hay ciudadesif(num =0)thenbegin
MessageDlg('No hay ninguna ciudad que coincida con ese código [nombre,pais].', mtWarning,[mbOK],0);
Exit;end;// Lista de horas (Lista)
TlkJSONBase(oHorasList):= AObjResp.Field['list'];// array de elementosSetLength(ATiempoProxHoras.TiempoHora, oHorasList.Count);// Quedarse con el primier elemento de la lista...for i :=0to(oHorasList.Count-1)dobegin// datos de la primera ciudad
TlkJSONBase(oHora):= oHorasList.Child[i];// datos básicos
ATiempoProxHoras.TiempoHora[i].dt_text:= GetAsString(oHora.Field['dt_txt'].Value);// convertir fecha-Hora
Str := ATiempoProxHoras.TiempoHora[i].dt_text;
ATiempoProxHoras.TiempoHora[i].dt:= EncodeDateTime(StrToIntdef(Copy(Str,1,4),0),StrToIntdef(Copy(Str,6,2),0),StrToIntdef(Copy(Str,9,2),0),StrToIntdef(Copy(Str,12,2),0),StrToIntdef(Copy(Str,15,2),0),StrToIntdef(Copy(Str,18,2),0),0);// Load Main
TlkJSONBase(oMain):= oHora.Field['main'];
ATiempoProxHoras.TiempoHora[i].Main.temp:= GetAsFloat(oMain.Field['temp'].Value);
ATiempoProxHoras.TiempoHora[i].Main.tempmin:= GetAsFloat(oMain.Field['temp_min'].Value);
ATiempoProxHoras.TiempoHora[i].Main.tempmax:= GetAsFloat(oMain.Field['temp_max'].Value);
ATiempoProxHoras.TiempoHora[i].Main.pressure:= GetAsFloat(oMain.Field['pressure'].Value);
ATiempoProxHoras.TiempoHora[i].Main.humidity:= GetAsInteger(oMain.Field['humidity'].Value);// Load weather
TlkJSONBase(OWList):= oHora.Field['weather'];
TlkJSONBase(oWeather):= oWList.Child[0];
ATiempoProxHoras.TiempoHora[i].Weather.id:= GetAsInteger(oWeather.Field['id'].Value);
ATiempoProxHoras.TiempoHora[i].Weather.main:= GetAsString(oWeather.Field['main'].Value);
ATiempoProxHoras.TiempoHora[i].Weather.desc:= GetAsString(oWeather.Field['description'].Value);
ATiempoProxHoras.TiempoHora[i].Weather.icon:= GetAsString(oWeather.Field['icon'].Value);end;
Result :=True;except// si hay error, FALSe
Result :=False;end;end;
function TForm1.ParseTiempoCiudadesHist(AObjResp: TlkJSONobject; var ATiempoProxHoras: TTiempoProxHoras): Boolean;
var
i, j, num, index:integer;
oHorasList, OWList:TlkJSONlist;
oHora, oCoord, oMain, oWind, oWeather:TlkJSONobject;
Str:String;
begin
// ini
Result := False;
// Si no está asignado salimos..
if not Assigned(AobjResp) then begin
Exit;
end;
// Si hay error no parseamos
if IsErrorResponse(AObjResp, errCode, ErrMsg) then begin
Exit;
end;
// proteccion para el parseo
try
// cod. devuelto (datos principales
ATiempoProxHoras.Cod := errCode;
num := AObjResp.IndexOfName('count');
if (num <> -1) then begin
num := GetAsInteger(AObjResp.Field['count'].Value);
end;
// si no hay ciudades
if (num = 0) then begin
MessageDlg('No hay ninguna ciudad que coincida con ese código [nombre,pais].', mtWarning, [mbOK], 0);
Exit;
end;
// Lista de horas (Lista)
TlkJSONBase(oHorasList) := AObjResp.Field['list'];
// array de elementos
SetLength(ATiempoProxHoras.TiempoHora, oHorasList.Count);
// Quedarse con el primier elemento de la lista...
for i := 0 to (oHorasList.Count - 1) do begin
// datos de la primera ciudad
TlkJSONBase(oHora) := oHorasList.Child[i];
// datos básicos
ATiempoProxHoras.TiempoHora[i].dt_text := GetAsString(oHora.Field['dt_txt'].Value);
// convertir fecha-Hora
Str := ATiempoProxHoras.TiempoHora[i].dt_text;
ATiempoProxHoras.TiempoHora[i].dt := EncodeDateTime(
StrToIntdef(Copy(Str, 1, 4), 0),
StrToIntdef(Copy(Str, 6, 2), 0),
StrToIntdef(Copy(Str, 9, 2), 0),
StrToIntdef(Copy(Str, 12, 2), 0),
StrToIntdef(Copy(Str, 15, 2), 0),
StrToIntdef(Copy(Str, 18, 2), 0), 0);
// Load Main
TlkJSONBase(oMain) := oHora.Field['main'];
ATiempoProxHoras.TiempoHora[i].Main.temp := GetAsFloat(oMain.Field['temp'].Value);
ATiempoProxHoras.TiempoHora[i].Main.tempmin := GetAsFloat(oMain.Field['temp_min'].Value);
ATiempoProxHoras.TiempoHora[i].Main.tempmax := GetAsFloat(oMain.Field['temp_max'].Value);
ATiempoProxHoras.TiempoHora[i].Main.pressure := GetAsFloat(oMain.Field['pressure'].Value);
ATiempoProxHoras.TiempoHora[i].Main.humidity := GetAsInteger(oMain.Field['humidity'].Value);
// Load weather
TlkJSONBase(OWList) := oHora.Field['weather'];
TlkJSONBase(oWeather) := oWList.Child[0];
ATiempoProxHoras.TiempoHora[i].Weather.id := GetAsInteger(oWeather.Field['id'].Value);
ATiempoProxHoras.TiempoHora[i].Weather.main := GetAsString(oWeather.Field['main'].Value);
ATiempoProxHoras.TiempoHora[i].Weather.desc := GetAsString(oWeather.Field['description'].Value);
ATiempoProxHoras.TiempoHora[i].Weather.icon := GetAsString(oWeather.Field['icon'].Value);
end;
Result := True;
except
// si hay error, FALSe
Result := False;
end;
end;
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
He actualizado el contenido de la web en DropBox para que estén en todo momento accesibles los ejemplos, artículos, documentación,… Más detalles de todo ello en esta entrada.
He incluido los últimos ficheros añadidos a las entradas, la última versión de las librerías GLibWMI y los últimos ficheros de otras secciones como la de las rxLib en este blog.
Si os vais a dar de alta os agradecería que usarais esta invitación, de esta forma a ambos nos ofrecen un poco más de espacio, que nunca va mal… ;-)
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
IBPIndexCalc es una aplicación que permite obtener multitud de datos (en general “el grado de dificultad”) de un Track/Ruta realizado en bicicleta (sea de carretera o de montaña). Aunque los datos podrían ser aplicados a cualquier track realizado en otra actividad.
Para ello el programa utiliza la web de IBPIndex (http://www.IBPIndex.com); Imprescindible para todos aquellos que salís en bici y utilizáis/generáis track con GPS.
Este índicxe IBP (Interactive Bicycling Parameters) se obtiene analizando los datos de latitud, longitud y altura en multitud de puntos del recorrido. A partir de estos puntos se calculan las distancias recorridas en los diferentes tramos de subidas y bajadas (1%, 5%, 10% etc..) se computan los % que representan sobre el total, los metros totales ascendidos, descendidos, los ratios medios de subida y de bajada, los Km. totales, y la distribución de los tramos de subida. Si queréis saber más y ampliar información sobre el tema visitad la web de IBPIndex (proceso de cálculo, corrección de errores, formato de puntuación,…).
IBPIndexCalc utiliza los componentes Indy para el acceso a la Web. Además implementa una clase derivada de TThread que permite que el pograma principal no se bloquee mientras espera la respuesta desde la web. Estructura de la Clase TWebThread:
{ : Clase para realizar consultas utilizando thread a la Web. }
TWebThread =class(TThread)private
IdHTTP: TidHTTP;
Stream: TIdMultipartFormDataStream;
FTrackFileName:string;
FwebBrowser: TWebBrowser;
FResponse:string;private
FURLNavigate:string;
FURLPDF:string;function _RepairLinks(StrPage:string;var URLpage:string;var UrlPDF:string):string;protectedpublic// ejecutar el procedimniento.procedure Execute;override;// componente de navegación.property webBrowser: TWebBrowser read FwebBrowser write FwebBrowser;// Fichero de Track/ruta.property TrackFileName:stringread FTrackFileName write FTrackFileName;// : Propiedad para recoger la respuesta desde la Web.property Response:stringread FResponse write FResponse;// URL de navegación.property URLNavigate:stringread FURLNavigate write FURLNavigate;// URL del PDF de respuesta.property UrlPDF:stringread FURLPDF;// : Constructor redefinido.constructor Create(AFileName:string; wb: TWebBrowser);end;
{ : Clase para realizar consultas utilizando thread a la Web. }
TWebThread = class(TThread)
private
IdHTTP: TidHTTP;
Stream: TIdMultipartFormDataStream;
FTrackFileName: string;
FwebBrowser: TWebBrowser;
FResponse: string;
private
FURLNavigate: string;
FURLPDF: string;
function _RepairLinks(StrPage: string; var URLpage: string;
var UrlPDF: string): string;
protected
public
// ejecutar el procedimniento.
procedure Execute; override;
// componente de navegación.
property webBrowser: TWebBrowser read FwebBrowser write FwebBrowser;
// Fichero de Track/ruta.
property TrackFileName: string read FTrackFileName write FTrackFileName;
// : Propiedad para recoger la respuesta desde la Web.
property Response: string read FResponse write FResponse;
// URL de navegación.
property URLNavigate: string read FURLNavigate write FURLNavigate;
// URL del PDF de respuesta.
property UrlPDF: string read FURLPDF;
// : Constructor redefinido.
constructor Create(AFileName: string; wb: TWebBrowser);
end;
Una vez que el programa obtiene respuesta de la Web, la analiza para detectar posibles errores y para extraer los links útiles al usuario. En este caso el PDF generado y la página de resultados.
La aplicación y la clase UTWebThread puede se útil, modificando determinados, para realizar un trabajo similar en otras páginas webs.
Es totalmente gratuíta y el código fuente está disponible.
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Es el error que muchas veces pienso que debería haber “saltado” en la aplicación, cuando reviso cierto código que debí escribir un día de esos en que mi cabeza está “nublada” (como los días de invierno…).
Pues Voilà!
A partir de la versión 2009 de Delphi ya está disponible y prometo usarla de aquí en adelante en mis nuevos desarrollos… ;-)
¿Que no os lo creéis? Basta con revisar la unit SysUtils.pas
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…
Acabo de empaquetar la versión 1.3 (beta) de la librería de componentes GLibWMI, basados en la WMI de Windows.
Básicamente he añadido nuevos componentes y he corregido algunos errores que incluía la demo general. Además he testado la librería en Delphi 2009 sin ningun problema a la hora de compilar. Doy por supesto que en todas las intermedias entre D7 y D2009 fucionará sin problemas.
Los componentes nuevos son:
CProcessInfo: Información acerca de los procesos que hay ejecutándose en el sistema..
CServiceInfo: Información detalleda de los servicios que hay instalados en el sistema..
CDesktopMonitorInfo: Información detallada sobre el monitor o dispositivo de visualización que hay en el sistema.
CComputerSystemInfo: Información acerca del sistema en General.
CStartupCommandInfo: Información acerca de los procesos que se ejecutan automáticamente cuando el usuario hace el Login en el sistema.
Embarcadero MVP.
Analista y Programador de Sistemas Informáticos.
Estudios de Informática (Ingeniería Técnica Superior) en la UPC (Universidad Politécnica de Barcelona).
Llevo utilizando Delphi desde su versión 3. Especialista en diseño de componentes, Bases de Datos, Frameworks de Persistencia, Integración Continua, Desarrollo móvil,…