Localizar más facilmente una vista Razor con Resharper

Si alguna vez habéis tenido que localizar y maquetar una web que inicialmente estaba en un idioma en varios sabréis que es algo que quita mucho tiempo y desespera profundamente.

Es un proceso lento, repetitivo y que requiere compilar para ver los cambios… vamos, una fiesta.

Como me ha tocado hacer lo propio con las nuevas vistas de Terminis me he planteado la pregunta, ¿Resharper no me podrá ayudar a hacerlo más rápido?

Respuesta rápida: NO por defecto, pero podemos mejorarlo un poco.

Resharper tiene una opción para refactorizar un string y moverlo a un fichero de recursos pero esta opción solo funciona en código interpretado no en texto suelto de vistas Razor :_(

 

Investigando un poco he encontrado un pequeño truco que permite convertir un trozo del HTML en “código interpretado” por el compilador y así poder recfactorizarlo a recurso: crear un surround template:

Template Explorer

Creando el Surround Template

Resharper usa los templates para ayudarte a codificar más rápido y son francamente útiles. En concreto, los surround templates, sirven para seleccionar un texto y envolverlo con, por ejemplo, un tag HTML.

Para nuestra pequeña “trampa” necesitamos crear uno que envuelva el texto seleccionado entre @(“TEXTO”) para que resharper pueda interpretarlo y moverlo a un fichero de recursos.

Para ello seleccionamos en el Template Explorer la opción de “Surround Templates” en los tabs de arriba, elegimos el scope “Razor” y pulsamos en “New Template”:

New Surround Template

Esto nos abrirá una ventana para que peguemos el código del template y le demos un nombre. Yo lo he llamado “@” (si, lo sé, super original..)

Este es el código:

@(“$SELECTION$”)

Luego, en la lista, tienes que arrastrarlo a la quick list para tenerlo más a mano (como en la imagen de arriba).

Bien, con esto ya tenemos el surround template listo y tan solo tenemos que usarlo.

Usandolo en nuestra vista Razor

Tenemos un texto en un h2 que queremos incluir en el fichero de recursos lo más rápido posible.

h2

Hacerlo de la forma “tradicional” implicaría ir al fichero de recursos, añadir uno nuevo, darle un nombre, copiar&pegar este texto, clonarlo para el resto de idiomas, localizar en cada idioma y volver a la vista de razor para sustituir el texto por la llamada al fichero de recursos: un coñazo.

Con surround template (y con los benditos shortcuts!):

1) CTRL + W hasta seleccionar toda la frase a localizar:

h2_1

2) CTRL + E , J: Surround with: @:

h2_2

3) CTRL + R, O: Refactor, Move To:

RefactorMoveTo

 

¡voilá! Resharper se encarga el solo de crear el recurso (en el fichero que le digas), sustituirlo en el Razor y dejarlo listo para clonarlo en el resto de idiomas.

ACTUALIZADO

El gran Subgurim me comenta una forma aún más rápida de refactorzar texto:

En el explorador de soluciones seleccionamos el proyecto y, en sus propiedades -> Resharper modificamos:

  • Localizable: True
  • Localizable inspector: Pessimistic

ResharperLocalizationProperties

 

Con esto habilitamos la opción de Refactor > Move To Resources en el menú de acceso rápido con ALT+ENTER lo cual hace el paso 3 mucho más rápido:

¡Gracias Maestro!


No es la solución que esperaba encontrar pero me ha ahorrado horas de tedioso copy&paste…

¡Nos vemos compilando!

Exportar base de datos SQL SERVER a un BLOB en Azure como backup

Decir que Azure, la plataforma Cloud de Microsoft, es una de las más potentes del mercado pese a su corto tiempo de vida no es algo nuevo aunque, precisamente por su juventud, nos encontramos con algunas carencias que hacen algo más complicado las gestiones típicas de un sistema en producción.

Una de estas carencias es la posibilidad de automatizar backups (copias de seguridad) de nuestras bases de datos SQL SERVER algo que necesitamos tener cuando nuestro proyecto pasa el estado de desarrollo.

 

La única posibilidad que nos ofrece Azure en este momento (25/06/2013) es exportar/importar nuestras bases de datos a un blob desde el panel de control a petición pero no podemos programar esta tarea para que se ejecute periódicamente.

 

Esta opción genera en uno de nuestros containers un blob con extensión .bacpac con la copia de seguridad de la base de datos escogida para poder importarla en cualquier momento.

La pregunta es, ¿cómo podemos hacer esto automáticamente? La respuesta, con una aplicación que llame periódicamente a la misma API REST que usa Azure para estas tareas.

 

Azure Sql Server API REST

Azure Sql Server expone un API REST con algunas tareas básicas que podemos invocar (con las debidas credenciales, claro está) para exportar o importar nuestras bases de datos contra Azure Storage.

Cada una de las regiones de Azure Sql Server tiene su propia url del servicio por lo que deberás asegurarte de usar la url correcta en función de en que región se encuentre tu base de datos:

 

 

DataCenter Endpoint
North Central US https://ch1prod-dacsvc.azure.com/DACWebService.svc/
South Central US https://sn1prod-dacsvc.azure.com/DACWebService.svc/
North Europe https://db3prod-dacsvc.azure.com/DACWebService.svc/
West Europe https://am1prod-dacsvc.azure.com/DACWebService.svc/
East Asia https://hkgprod-dacsvc.azure.com/DACWebService.svc/
Southeast Asia https://sg1prod-dacsvc.azure.com/DACWebService.svc/
East US https://bl2prod-dacsvc.azure.com/DACWebService.svc/
West US https://by1prod-dacsvc.azure.com/DACWebService.svc/

 

Las dos tareas expuestas por este servicio son “Export” e “Import” (para exportar e importar respectivamente) por lo que, por ejemplo, para solicitar una exportación de una base de datos alojada en el Norte de Europa deberíamos hacer un POST contra la url: https://db3prod-dacsvc.azure.com/DACWebService.svc/Export

 

Solicitando Exportación desde código

Para automatizar el proceso de exportación podemos programar un pequeño Worker Role de Azure, un servicio de Windows que se ejecute en uno de nuestros servidores locales o incluso que lo implemente nuestra propia web de administración. En mi caso dispongo de un Worker Role propio con varias tareas de mantenimiento que se ejecutan cada cierto tiempo por lo que me fue muy fácil incluir una nueva tarea para hacer este backup.

Para hacer esta exportación, como hemos comentados antes, basta con hacer un POST contra la [url del servicio] + “/Export” incluyendo en el cuerpo de la petición un xml con los datos necesarios para la tarea.

 

Este xml que tenemos que postear tiene el siguiente formato:

[code language=”xml”]

<ExportInput
xmlns="http://schemas.datacontract.org/2004/07/Microsoft.SqlServer.Management.Dac.ServiceTypes"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<BlobCredentials
i:type="BlobStorageAccessKeyCredentials">
<Uri>[URL del Blob a crear]</Uri>
<StorageAccessKey>[Clave de acceso del Azure Storage]</StorageAccessKey>
</BlobCredentials>
<ConnectionInfo>
<DatabaseName>[Nombre de la base de datos a exportar]</DatabaseName>
<Password>[Password del usuario de la base de datos]</Password>
<ServerName>[Nombre del servidor en el que se encuentra la base de datos]</ServerName>
<UserName>[Usuario de acceso a la base de datos]</UserName>
</ConnectionInfo>
</ExportInput>

[/code]

Los parámetros que debes rellenar son:

  • [URL del Blob a crear]
    • Url completa del blob que vas a crear con “.bacpac” al final.
      • Ej: https://mistorageenazure.blob.core.windows.net/bak/backup-2013-06-25_09-49.bacpac
  • [Clave de acceso del Azure Storage]
    • La “Primary Access Key” de nuestro Storage en Azure. La podemos encontrar en el panel de administración de Azure > Storage > [el storage al que queremos acceder] > Manage Access Keys
  • [Nombre del servidor en el que se encuentra la base de datos]
    • Nombre completo del servidor de SQL SERVER en el que se encuentra la base de datos a exportar (debe terminar en “database.windows.net”)
      • Ej: server.database.windows.net
  • Datos de la BD
    • Nombre, usuario y contraseña de la base de datos a exportar

 

Con este xml generado ya solo necesitamos hacer un POST contra la url del servicio para solicitar la tarea de exportación.

Este servicio nos devuelve un GUID para la posterior comprobación del estado de la tarea. Podemos guardarlo si queremos para poder saber si ha terminado con éxito o no.

Aquí un ejemplo con el código completo:

[code language=”csharp”]
private Guid RequestExport(string databaseName, string containerUrl, string storageAccessKey, string blobName)
{
// Método que devolvería la URL del Servicio en función de la Región. Yo le paso un tipo enum propio por comodidad
var managementUrl = GetAzureManagementUrlByRegion(AzureRegions.NorthEurope);

var request = WebRequest.Create(managementUrl + "/Export");
request.Method = "POST";

var dataStream = request.GetRequestStream();
// Método que genera el XML que se le pasa como Body con el formato comentado anteriormente
var body = GetExportToBlobBodyRequest(blobUrl, storageAccessKey, databaseName);
var utf8 = new UTF8Encoding();
var buffer = utf8.GetBytes(body);
dataStream.Write(buffer, 0, buffer.Length);

dataStream.Close();
request.ContentType = "application/xml";

// La respuesta HTTP contiene el GUID que representa la tarea serializado como XML
using (var response = request.GetResponse())
{
var encoding = Encoding.GetEncoding(1252);
using (var responseStream = new StreamReader(response.GetResponseStream(), encoding))
{
using (var reader = XmlDictionaryReader.CreateTextReader(responseStream.BaseStream, new XmlDictionaryReaderQuotas()))
{
var serializer = new DataContractSerializer(typeof(Guid));
return (Guid)serializer.ReadObject(reader, true);
}
}
}
}
[/code]

¡Listo! Nuestra tarea de exportación ya se está lanzando y, si todo funciona como debe, en breve se creará un nuevo blob con el contenido de nuestra base de datos para poder importarlo en caso de catástrofe o para replicarlo en otra base de datos distinta para hacer pruebas.

Comprobando el estado de la tarea

Si queremos saber si todo ha ido bien o ha fallado algo podemos hacer GET a otro método del API REST de Azure llamado “Status” indicando el GUID obtenido en la petición de la tarea. Para ello basta con hacer GET de la siguiente url:

[Url del servicio API REST de tu Región]/Status?servername=[servidor de base de datos completo]&username=[usuario de la base de datos]&password=[password de la base de datos]&reqId=[GUID de la tarea]

 

Esta url nos debe devolver un XML con información del estado de la tarea.

 

¡Hecho! Con un simple cliente HTTP podemos hacer exportaciones e importaciones periódicas y automáticas de nuestra base de datos y así protegernos ante cualquier problema que podamos tener.

Como siempre para cualquier duda ya sabéis dónde podéis encontrarme.

 

¡Un saludo y nos vemos Compilando!

Configurar HTTPS en un WebRole de Azure

 

Parece mentira pero algo tan sencillo como permitir el acceso por HTTPS con un dominio personalizado en Azure es algo que no es trivial.

Para empezar, a día de hoy 2 de Abril del 2013, no puedes usar certificados de seguridad en un Web Site de Azure si no estás usando su dominio “azurewebsites.net” por lo que nos hemos visto obligados a mover la web a un WebRole el cual tiene menos opciones de deployment y es más complejo que el Web Site solo para poder poner habilitar el acceso a https://www.midominio.com… lamentable.

Además el proceso completo para poder pedir, instalar y configurar el certificado de seguridad no es nada sencillo así que, para todos los que se vayan a pelear con este tema hasta que lo mejoren, les dedico este artículo.

Crear la solicitud del Certificado

Para poder configurar nuestro certificado de seguridad en Azure necesitamos conocer la clave privada con la que se generó la petición del certificado. Por este motivo no podemos crear la solicitud del certificado desde el IIS ya que no controlamos con qué clave se firma.

El mejor método de hacer esta solicitud es desde el OpenSSL siguiendo estos pasos:

  1. Descargar e instalar OpenSsl para Windows: http://slproweb.com/products/Win32OpenSSL.html
  2. Abrir una consola (cmd.exe) y establecer la variable de entorno para el fichero de configuración del OpenSSL
    set OPENSSL_CONF=c:\[Ruta a la carpeta donde has instalado el OpenSSL]\bin\openssl.cfg
  3. Crear la solicitud de certificado y creación de la clave privada:
    openssl req -nodes -newkey rsa:2048 -keyout private.key -out request.csr
    

    Asegúrate de que tienes permisos de escritura en la carpeta en la que estás depositando el .key y el .csr.
    Al lanzar esta llamada al openssl se te pedirá que rellenes una serie de datos para la solicitud del certificado. Ves introduciendo los datos y pulsa ENTER.
    También se pedirá una contraseña. Anótala ya que la usaremos más adelante.
    IMPORTANTE en “Common Name (e.g. server FQDN or YOUR name) []:” pon el nombre de dominio que quieres proteger (ej: www.compilando.es)

Con el “.csr” creado ya podemos pedir a nuestro proveedor de SSL de confianza que nos genere un certificado de seguridad instalable en nuestro servidor.

 

Exportar el fichero .PFX

Para poder configurar el Web Role en Azure necesitamos obtener el fichero que contiene el certificado de seguridad y la clave privada que generó la petición por eso debemos obtener este fichero .pfx mediante otra llamada al OpenSSL usando el “.crt” que nos ha enviado el proveedor de SSL junto con el “.key” que creamos en el paso anterior.

Supongamos que nuestro proveedor nos envía el fichero de certficado llamado “compilando.crt”

Para ello seguimos los siguientes pasos:

  • Abrimos el certificado que nos envía el proveedor, si no está en formato pkcs12 tenemos que convertirlo antes. Para ello abrimos una consola (cmd.exe) y ejecutamos el siguiente comando de openssl (ejemplo de conversión desde pkcs7):
    openssl pkcs7 -print_certs -in compilando.crt -out compilando_pkcs12.crt
  • Con el certificado ya en formato pkcs12 exportamos el pfx:
    openssl pkcs12 -export -in compilando.crt -inkey private.key -out azure.pfx
  • En la consola nos solicitarán la contraseña que pusimos en el primer paso cuando creamos “private.key” (por eso dije de anotarla ;-))

Con esto obtenemos un fichero llamado “azure.pfx” que ya podemos usar para configurar nuestro WebRole.

 

Configurar HTTP en Azure

Con el certificado correctamente generado y exportado ya podemos configurar nuestro WebRole para disponer de un endpoint funcionando con HTTPS.

Lo primero que debemos hacer es subir el .PFX que acabamos de generar a Azure. 

Para ello nos conectamos al panel de administración de Azure (https://manage.windowsazure.com/) y hacemos lo siguiente:

  • Cloud Services > [Web Role] > Certificates > Upload
  • Escogemos el fichero .PFX que acabamos de crear y escribimos la contraseña (la misma que pusimos al crear el .key y al exportar el .pfx)

 

  • Una vez subido veremos el certificado en el listado y copiamos el GUID de la columna “Thumbprint”

Ahora lo que nos queda es configurar el EndPoint en el Visual Studio. Para ello vamos a la solución en la que tenemos nuestro proyecto de Azure y editamos la definición del Servicio (ServiceDefinition.csdef) y los ficheros de configuracón del Servicio (ServiceConfiguration.XXXX.cscfg) tal y como se ve en los ejemplos que hay a continuación:

ServiceDefinition.csdef

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="Compilando.WebRole" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2012-10.1.8">
  <WebRole name="Compilando.WebRole" vmsize="Small">
<Sites> <Site name="Web"> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" /> <Binding name="HttpsIn" endpointName="HttpsIn" /> </Bindings> </Site> </Sites> <Endpoints> <InputEndpoint name="Endpoint1" protocol="http" port="80" /> <InputEndpoint name="HttpsIn" protocol="https" port="443" certificate="www.compilando.es" /> </Endpoints> <Certificates> <Certificate name="www.compilando.es" storeLocation="LocalMachine" storeName="CA" /> </Certificates> </WebRole> </ServiceDefinition>

Como veis, se crea un nuevo EndPoint con el protocolo https apuntando al puerto 443 y usando el nuevo certificado que hemos subido.

ServiceConfiguration.Cloud.cscfg

<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="Predeploy.Terminis.Web.Azure" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="3" osVersion="*" schemaVersion="2012-10.1.8">
  <Role name="Compilando.WebRole">
<Instances count="1" /> <Certificates> <Certificate name="www.compilando.es" thumbprint="F319BC716E1B17FC8824B9325059EC503B6609AE" thumbprintAlgorithm="sha1" /> </Certificates> </Role> </ServiceConfiguration>

En este caso, en la configuración Cloud de nuestra web “Compilando.WebRole” indicamos que el certificado llamado “www.compilando.es” tiene el Thumbprint que hemos copiado del panel de control de Azure. Con esto ya podríamos publicar el WebRole (recordando subir los cscfg y csdef actualizados) para que use el nuevo certificado y ya podríamos visitar nuestra web https://www.compilando.es sin problema alguno :)

 

¡Nos vemos Compilando!

Lanzar automáticamente tests de QUnit desde TeamCity

 

 

Como comentaba en el anterior post estoy investigando sobre testeo de Javascript/Jquery desde Visual Studio y para ello he optado por usar el framework QUnit.

Después de las primeras pruebas y solventar los primeros problemas (sobre todo como “mockear” las llamadas ajax o ciertas peticiones a nivel de servidor) ha llegado el momento de añadir a nuestro servidor de integración continua (en nuestro caso el TeamCity) un nuevo paso para que ejecute automáticamente estos tests cada vez que alguien haga un commit.+

 

El problema de esto radica en que TeamCity no dispone de un driver nativo para ejecutar QUnit ni para lanzar un navegador y leer los resultados así que para que los tests de QUnit se ejecuten como un test más necesitamos:

  1. Un navegador que lance nuestra web de pruebas
  2. Un dirver que le diga al TeamCity el resultado de cada test (usando los TeamCity Service Messages)

 

PhantomJS: Ejecutando JavaScript desde la línea de comandos

Lanzar un navegador por cada test de QUnit y leer su resultado es como matar moscas a cañonazos. Lo que queremos es simple: ejecutar javascript y enviarle al TeamCity un mensaje con la respuesta.

Para ello necesitamos un intérprete de Javascript lo más ligero posible y que se pueda lanzar desde el cmd de Windows. Para ello hemos optado por usar PhantomJS.

PhantomJS nos permite ejecutar un fichero .js como si de un navegador se tratara con la ventaja de que, al no tener interfaz gráfica, tan solo ejecuta el javascript y escribe en el log lo que le digamos.

 

Ahora necesitamos un script que ejecute nuestros tests y escriba por consola mensajes para el TeamCity.

QunitTeamCityDriver

Para hacernos la vida más fácil disponemos en NuGet de una librería llamada “QUnitTeamCityDriver” que nos añadirá a nuestro proyecto dos ficheros javascript:

  • QUnitTeamCityDriver.phantom.js
    • Script ejecutado por el PhantomJs al que le pasaremos como parámetro el fichero .html que contiene los tests QUnit
  • QUnitTeamCityDriver.js
    • Script encargado de leer la respuesta del PhatomJS y escribir en consola los mensajes necesarios para integrarlo con el TeamCity
 
Con estos dos ingredientes tenemos todo lo necesario para crear un nuevo Build Step en TeamCity para que se lancen solitos los tests QUnit.
 

Configurando TeamCity para lanzar los tests QUnit mediante PhantomJS

Como decía al principio TeamCity no soporta de manera nativa la ejecución de tests QUnit por lo que necesitamos un ejecutable externo que se encargue de interpretar javascript y enviar la respuesta al TeamCity.

Primero, descargamos en el servidor de TeamCity el PhantomJS y lo dejamos en una ruta reconocible (por ejemplo, C:\tools\phatomjs). Si tienes más de un agente recuerda hacer este paso en todos ellos.

En segunto lugar. desde la interfaz de administrador del TeamCity, creamos un nuevo Build Step de tipo “Command Line“, le ponemos el nombre que queramos y establecemos la ruta del PhatonmJS y los parámetros.

¡Importante! Hay que pasarle dos parámetros al PhatomJs, el primero es la ruta al fichero “QUnitTeamCityDriver.phantom.js” descargado previamente del paquete del NuGet, el segundo (bueno, realmente es un parámetro que le pasamos a QUnitTeamCityDriver.phantom.js) es la ruta del fichero HTML que contiene las pruebas tal y como explicamos en el anterior post.

¡OJO CON LAS RUTAS! Recuerda que, por defecto, TeamCity ejecuta los steps desde el directorio de checkout (aunque puedes modificarlo añadiendo otra ruta en el Working Directory del step).

El resultado debe de ser algo similar a esto:

Una vez hecho esto ya podremos ejecutar el Build y veremos como los tests se ejecutan de forma habitual como si fueran de NUnit indicandonos en verde o rojo el resultado de los mismos :)

 

Espero que os sea útil.

 

¡Nos vemos Compilando!

Testeo de javascript/jquery desde Visual Studio usando QUnit

 

 

Conforme pasa el tiempo la importancia del javascript en nuestros sitios web se hace más evidente y, en demasiadas ocasiones, esto se olvida y se relega dejando todo nuestro código .js fuera de la cobertura de tests.

En el nuevo proyecto que estoy desarrollando en Avanzis me he propuesto tener el mayor Code Coverage posible y, para ello, voy a testear también el javascript que escriba.

Para ello necesito un modo de hacerlo de forma cómoda y rápida y que, al ser un proyecto NET MVC, cumpla las siguientes condiciones:

  • Los tests de javascript se puedan lanzar desde Visual Studio.
  • El TeamCity sea capaz de lanzarlos automáticamente en cada compilación (o en un Nightly Build en caso de que tarde mucho)
  • Se pueda calcular el Code Coverage
Con estas tres premisas me he lanzado a investigar y he encontrado la combinación perfecta: QUnit + NQUnit + JSCoverage
¿Y como monto este puzzle? ¡Vamos a ello!
 
Este primer post explica como configurar Visual Studio para poder lanzar test QUnit de forma sencilla. En otros post hablaremos sobre NQUnit, como integrarlo con TeamCity y como usar JSCoverage.

Proyecto de QUnit en Visual Studio

QUnit es un framework de Javascript para realizar pruebas unitarios desarrollado por la gente de jQuery para testear sus propios plugins.

El modo más cómodo de integrar QUnit en Visual Studio es instalar el paquete de NuGetQUnit for ASP.NET MVC” (http://nuget.org/packages/QUnit-MVC) en un nuevo proyecto web (en mi ejemplo: MiProyecto.Javascript.Tests) para que nos cree una estructura similar a esta:

 

 

En Content tendremos el css necesario para mostrar la web de resultados de QUnit.

“qunit.js” es la propia librería de QUnit.

Scripts es la carpeta en la que vamos a crear la estructura de carpetas de nuestros tests. En mi caso he optado por crear una carpeta “Tests” para los ficheros .js de test de QUnit y otra llamada como el proyecto (MiProyecto/Common) para los ficheros a testear.

Obviamente estos ficheros (miproyecto.common.math.js) están en su carpeta correspondiente dentro del proyecto de la web MVC por lo que debemos hacer es agregarlos como enlace desde la carpeta del proyecto de test: (en el ejemplo, botón derecho sobre “Common” > Add Existing Item > Buscamos el .js en su carpeta original y seleccionamos en el desplegable de “Add” la opción “Add as Link“:

De este modo puedes acceder al .js original desde el proyecto de Test sin tener que copiar el fichero.

Por último solo necesitamos una página html en la que incluir estos ficheros javascript con una estructura prefijada por QUnit para mostrar los resultados.

El código de la página debe ser similar a este:

<!DOCTYPE html>
<html>
<head>
    <title>QUnit Test Suite</title>
    <link rel="stylesheet" href="Content/qunit.css" type="text/css" media="screen" />
    <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js"></script>
    <script type="text/javascript" src="Scripts/qunit.js"></script>
    <script type="text/javascript" src="Scripts/MiProyecto/Common/math.js"></script>
    <script type="text/javascript" src="Scripts/Tests/math.tests.js"></script>
</head>
<body>
    <h1 id="qunit-header">
        MiProyecto QUnit Test Suite</h1>
    <h2 id="qunit-banner">
    </h2>
    <div id="qunit-testrunner-toolbar">
    </div>
    <h2 id="qunit-userAgent">
    </h2>
    <ol id="qunit-tests">
    </ol>
    <div id="qunit-fixture">
    </div>
</body>
</html>

Como ves hay que añadir tanto los scripts propios de QUnit como los ficheros a testear y los propios ficheros de tests.

Nota: Desde Resharper se pueden lanzar los tests directamente sin tener que ejecutar esta página PERO tiene ciertas limitaciones (no se puede usar la creación dinámica de valores en el qunit-fixture y no se puede depurar facilmente) por lo que al final opté por hacer la página y ejecutarla manualmente para poder depurar con Firebug.

¡Bien! Ya tenemos la estructura creada pero, ¿cómo se escriben los tests? ¡Allá vamos!

 

Tests en QUnit

Supongamos que tenemos el siguiente fichero javascript en nuestra web (miproyecto.common.math.js) que tiene un par de métodos para hacer sumas, uno que simplemente suma dos números y otro que obtiene el valor de dos inputs por id, los suma y devuelve un span con el resultado:

//Suma dos valores SOLO si son números 
var sumNumbers = function (x, y) {
    if (typeof x === "number" && typeof y === "number")
    { return x + y; } else {
        return "error";
    }
}

//Obtiene el valor de dos elementos por su id, los suma (si son números) y crea un <span> con el resultado
var createSpanSumResultFromInputs = function (idX, idY) {

    var spanResultado = $(document.createElement('span'));

    var x = $("#" + idX).val();
    var y = $("#" + idY).val();
    var result = sumNumbers(x, y);
    if (typeof result === "number") {
        var stringResult = x + '+' + y + '=' + result;
        spanResultado.InnerHtml = stringResult;
    } else {
        spanResultado.InnerHtml = "error";
    }

    return spanResultado;
}

Estos dos ejemplos sirven para demostrar como hacer tests simples para validar entrada de datos, validar resultado y validar modificación de la DOM (lo más común en nuestros scripts).

Para nuestro fichero de test creamos un nuevo fichero js (miproyecto.common.math.tests.js) que está estructurado de la siguiente forma:

// Referencia: Ruta relativa del fichero javascript a testear (para que Resharper la incluya antes de lanzar el test)
/// <reference path="/Scripts/Terminis/Common/math.js"/>

// Clase que engloba todos los tests. Es aquí donde se especifica el SetUp y el TearDown
module('Math Tests', {
    setup: function () {
        // setup code

    },
    teardown: function () {
        // teardown code
    }
});

// Método de test
test('nombre del test', function () {
    //... Asserts
});

Como ves la estructura es similar a la de una clase de test de NUnit. Tenemos SetUp y TearDown y varios métodos de tests con varios asserts (o afirmaciones). ¡Importante! no olvidar el “<reference>” o nuestros tests fallarán al invocar los métodos a probar.

 

Para empezar vamos a probar nuestro método “sum” validando que solo sume dos números y devuelva el valor correcto o el string “error” en caso contrario:

test('Sum Validation.', function () {
    equal(sumNumbers("", ""), "error", "sumar dos cadenas vacias devuelve error");
    equal(sumNumbers("zadasdad", "asdadsa"), "error", "sumar dos textos devuelve error");
    equal(sumNumbers("asdasd", 1), "error", "sumar texto y número devuelve error");
    equal(sumNumbers(1, "asdasdasd"), "error", "sumar número y texto devuelve error");
});

test('Sum Correct Results.', function () {
    equal(sumNumbers(1, 2), 3, "suma de dos enteros");
    equal(sumNumbers(-1, -2), -3, "suma de dos negativos");
    equal(sumNumbers(-2, 1), -1, "suma mixta");
    equal(sumNumbers(1, 2.5), 3.5, "suma de entero y decimal");
    equal(sumNumbers(1.5, 2.5), 4, "suma de dos decimales");
});

Es muy sencillo hacer los asserts. Tan solo hay que hacer uso de la API de QUnit (usando “ok”, “equal”, “notEqual”, “raises”, etc…), poner el resultado de la llamada, el valor esperado y un mensaje para identificar el tipo de afirmación que estamos probando.

 

En el segundo método las pruebas se complican ya que los valores de entrada dependen de elementos de la DOM y el resultado es un <span> por lo que necesitamos crear lo que necesitamos en el SetUp antes de lanzar los tests:

module('createSpanSumResultFromInputs Tests', {
    setup: function () {
        // setup code
        $('#qunit-fixture').append('<input type="text" id="xTest" value="1"/>');
        $('#qunit-fixture').append('<input type="text" id="yTest" value="2"/>');
        $('#qunit-fixture').append('<input type="text" id="wrongValue" value="this is not a number"/>');
    }
});

En el SetUp de este nuevo módulo (solo se ejecutará este SetUp antes de las siguientes llamadas “test()”) hemos creado 3 inputs, dos con valores correctos y uno incorrecto para tests de validación, como si de una página “mockeada” se tratara. 

Para crearlos los hemos añadido al contenedor con id “qunit-fixture“, este elemento es un div cuyo contenido se crea y de destruye en cada ejecución por lo que podemos guarrear todo lo que queramos con él.

Los tests en este caso no diferirían demasiado a los ya visto con anterioridad:

test('Validation Tests', function () {
    equal(createSpanSumResultFromInputs("not exists", "yTest").text(), "error", "Si no existe el idX devuelve error");
    equal(createSpanSumResultFromInputs("xTest", "not exists").text(), "error", "Si no existe el idY devuelve error");
    equal(createSpanSumResultFromInputs("xTest", "wrongValue").text(), "error", "Si uno de los dos no es un número devuelve error");
});

test('Correct Test', function () {
    equal(createSpanSumResultFromInputs("xTest", "yTest").text(), "1+2=3" , "Obtiene los dos valores de sendos input's y devuelve <span> con la operacion");
});

Con esto ya sabemos todo lo básico de los test con QUnit. Existen muchas más cosas como el asyncTest() para peticiones que incluyan callbacks que son harina de otro costal.

 

El resultado es una web similar a esta con todos los test organizados por módulos > tests > asserts pudiendo relanzar test, ocultar test correctos y depurar con FireBug:

 

Con esto ya sabemos la base para empezar a chapurrear tests de javascript en nuestro Visual Studio :)

En la próxima entrega hablaremos sobre como lanzar estos tests desde un servidor de integración continua (como TeamCity) y calcular el Code Coverage.

 

Un saludo.

¡Nos vemos Compilando!

Configurar Git (BitBucket) en Visual Studio 2010 y no morir en el intento

 

Que Git se ha convertido en el más famoso y mejor controlador de versiones de código es una cosa que ya sabéis pero, ¿cómo puedo configurar las herramientas necesarias para poder trabajar con un repositorio Git en mi Visual Studio 2010?

El objetivo de este pequeño tutorial es conseguirlo sin morir en el intento

Nota: Este tutorial no explica el funcionamiento de un control de versiones por lo que doy por supuesto que todo el mundo sabe lo que es un commit, push, pull, branch, etc… Otro día haré un artículo dedicado a explicar más a fondo como funciona un control de versiones :)

 

¿BitBucket o GitHub?

¡Para empezar! Necesitamos una cuenta en algún servicio de repositorio de Git (si no dispones de uno local o el de tu empresa).

Actualmente existen dos grandes servicios gratuitos de Git que son GitHub y BitBucket. No voy a entrar a discutir cual es mejor en este artículo, solo diré que BitBucket te permite tener, de forma gratuita, repositorios privados lo cual es perfecto para esas pequeñas aplicaciones que tienes en casa y quieres salvaguardar.

Es por este motivo principalmente por lo que yo uso BitBucket como Source Control :)

 

¿Ya tienes cuenta en BitBucket? ¡Descarguemos Git!

 

Descargando y Configurando Git para Windows

Bien, lo primero que necesitamos es descargar Git para Windows el cual podemos encontrar aquí: http://code.google.com/p/msysgit/downloads/list

Descarga e instala la última versión disponible.

 

No hay que modificar casi nada durante el proceso de instalación. La única opción que recomiendo modificar es la de “Adjusing your PATH environment” la cual aconsejo cambiar de “Use Git Bash only” a “Run git from the Windows Command Prompt” tal y como se ve en la siguiente captura:

 

El resto lo puedes dejar igual.

 

¡Bien! ¡Ya lo tenemos instalado! Ahora tenemos que configurarlo para que funcione con nuestra cuenta de BitBucktet.

Para ello ejecutamos el “Git Bash” (si, es una consola, no te asustes, jeje) e introducimos la configuración global de nuestro usuario de BitBucket e Email escribiendo:

git config --global user.name "tu usuario de BitBucket aquí"

git config --globla user.email "tu email de BitBucket aquí"

 

Con esto ya lo tenemos!

Ahora vamos a configurar las herramientas en el Visual Studio 2010.

Configurando Git en Visual Studio 2010

Debido a que Visual Studio no incluye Git como control de código por defecto (solo incluye SourceSafe y Team Foundation Server) necesitamos instalar una pequeña extensión de Git para que funcione.
Para ello vamos a “Tools > Extension Manager” o “Herramientas > Administrador de Extensiones” en castellano y, en la Galería Online buscamos “Git” para instalar el “Git Source Control Provider“:

Una vez instalado lo escogemos como Source Control por defecto en “Herramientas > Opciones > Source Control > Selección de Complemento > Git Source Control Provider”

 

Lo próximo que debemos hacer es abrir (o crear) la solución que queremos subir a BitBucket y, pulsando botón derecho sobre el nombre de la solución clickamos en “New Repository“.

Esto creará un nuevo repositorio Git en el mismo directorio en el que está la solución.

Verás que en el “Solution Explorer” aparecen unos símbolos con un “+” amarillo. Esto indica que el fichero es nuevo y no se encuentra en tu repositorio local.

Haciendo click derecho de nuevo sobre la solución y pulsando en “Pending Changes” podremos ver el listado de ficheros pendientes, escribir un comentario y hacer el primer commit contra tu repositorio local.

¡Ya está! ¡Ya tenemos configurado Git para Visual Studio! Eso si, de momento solo lo deja en local y BitBucket ni lo hemos usado.

¿Qué toca ahora? Configurar Git Bash para que suba nuestros commits a BitBucket.

 

Configurar Remote y hacer Push desde Visual Studio a BitBucket

De nuevo botón derecho en la solución > Pending Changes > Git Bash y se nos abrirá la consola de Git. Ahora tenemos que configurar el acceso remoto.

Para ello escribimos lo siguiente:

git remote add origin https://usuario@bitbucket.org/nombre_del_repositorio.git

Supongamos que mi usuario es “vfportero” y mi repositorio en BitBucket se llama “demo”. El remote sería así:

git remote add origin https://vfportero@bitbucket.org/demo.git

 

¡Perfecto! Con esto ya podemos escribir: 

git push

Nos pedirá el password de BitBucket y, una vez escrito, y el bash solito se encargará de subir los ficheros al repositorio remoto :)

 

Espero que os haya servido de ayuda.

¡Nos vemos Compilando!

Primeros pasos desarrollando en Windows Phone: Consejos útiles

Windows Phone 7 es el nuevo sistema operativo móvil de Microsoft con el que pretende competir con dos grandes ya asentando en el mercado de los operativos para smartphone como iOS y Android.

Windows Phone 7 pretende reinventar el concepto de operativo movil apostando fuerte por un resideño completo de la interfaz (la famosa Metro UI) así como la integración con otros sistemas como XBox Live y Windows 8.

Yo, como buen fan de los productos de Microsoft, no podía perderme esta nueva entrada de los de Redmond al mercado móvil y es por eso que me aventuré a desarrollar una aplicación para el Marketplace en un principio por aprender pero, conforme le he ido dando forma, pensando en, ¿por qué no? ganar algún eurillo :)

 

Más adelante le dedicaré un post a mi primera app de Windows Phone “Echemos cuentas” (que ya está en proceso de aceptación por parte de Microsoft) así que el motivo de este artículo es intentar ayudar a los que, como yo, quieran subirse al barco de Windows Phone Marketplace y no sepan por donde empezar.

¡Aquí van unos cuantos consejitos!

 

¡Empecemos! ¿Qué me tengo que descargar?

Bien, partimos de la base de que eres un desarrollar .NET y que tienes el Visual Studio instalado (y si no ya tardas, jeje) por lo que tenemos que descargar e instalar es el SDK 7.1 de Windows Phone:

Estas herramientas incluyen todo lo necesario para crear un proyecto para Windows Phone así como el emulador para probarlo y depurarlo, herramientas de testeo previo a la publicación al Marketplace y el Expression Blend para poder diseñar los formularios WPF de forma sencilla y eficaz.
 

Bien, ¿por dónde empiezo?

Esto puede parecer un mundo si no damos los pasos correctos y, como no quiero abrumar con mucha información os comentaré los pasos que yo hice hasta poder terminar con éxito mi primera aplicación:

Revisa los “Quick Starts” del App Hub

App Hub es el punto de encuentro de todos los desarrolladores de Windows Phone y XBox Live en el que encontraremos tutoriales, herramientas, recursos y los foros en los que preguntar nuestras dudas.

Un ejemplo de estos tutoriales es el clásico “Hello World” que ilustra lo fácil que es crear un nuevo proyecto en Windows Phone y lanzarlo en nuestro emulador o teléfono: 

Con esto tienes material para probar, aprender y coger soltura con el framework.
 

No inventes la rueda: usa los controles Silverlight de Codeplex

Los controles por defecto del SDK están muy bien ya que te permiten montar una interfaz Metro sin apenas esfuerzo pero si de verdad queremos sacarle jugo a nuestra aplicación y que deslumbre a todo aquel que la use no te compliques y usas los controles Silverlight para Windows Phone de Codeplex:

Controles como el LongListSelector o el ExpanderView harán nuestro trabajo de diseño y funcionalidad muchísimo más fácil. 
Además estos controles son OpenSource y se van actualizando periodicamente así que no pierdas de vista Codeplex!
 

No tengas miedo y pregunta en los foros de desarrolladores

Si algo tiene la comunidad de desarrolladores de Windows Phone de habla hispana es una gran predisposición para ayudar a los demás, resolver sus dudas, dar consejos y crear comunidad.

Todo esto se ve plasmado de forma clara en los más que útiles foros de MSDN para Desarrollo de Windows Phone que modera el gran Josue Yeray (un referente dentro del mundo del desarrollo Windows Phone):

En el foro podrás preguntar cualquier duda que tengas desde aspectos técnicos hasta dudas sobre el modo de publicar una app en el Marketplace.
Echa un vistazo y plantea tus dudas. Verás como en breve un desarrollador como tu te echa una mano :)
 

Y, ¿qué tipo de aplicación hago?

A esta pregunta hay dos posibles respuestas.

Puedes hacer algo que te sea útil / interesante a ti y que no haya nada en el Marketplace que lo haga como tu quieres (esa es la ventaja de poder programar lo que quieras desde el mismo Visual Studio y poder instalarlo directamente en tu movil Windows Phone). En mi caso fue solventar un problema de gestión que tenemos en mi grupo de amigos a la hora de hacer las cuentas en los viajes, cenas, cumpleaños, etc… así que acabé programando una aplicación dedicada en la que yo era mi propio cliente.

 

Por otro lado, si quieres ganar dinero con la aplicación, lo que te recomiendo es buscar un nicho de mercado en el Marketplace y hacer una aplicación que rellene ese hueco. También puedes fijarte en aplicaciones que han tenido éxito en otras plataformas y, no copiar, si no hacer una versión con características similares aprovechando toda la potencia de la interfaz Metro y los Live Tiles de Mango.

Windows Phone 7 es una plataforma joven y aún quedan muchos tipos de aplicaciones por hacer así que busca algo que pueda interesar al público y ¡ponte con ello!

Ah! Y no desesperes si tu aplicación no funciona del todo bien en el mercado. Puedes publicar las aplicaciones que pago que quieras y hasta 100 gratuitas (a partir de 100 se pagan 19.90$ por cada publicación) así que no desesperes y sigue probando.

Quien sabe… a lo mejor estás detrás del nuevo WhatsApp 😉

 

¿Dónde consigo material más avanzado?

Si ya has hecho los tutoriales, tienes una buena idea y las estás llevando a cabo es posible que te surjan dudas sobre cómo hacer ciertas cosas o sobre como utilizar ciertos controles.

Como he comentado antes los foros son muy útiles pero, para estas situaciones, lo que realmente me ha sacado las castañas del fuego es el libro de Josuey Yeray: “Windows Phone 7.5: Desarrollo de aplicaciones en Silverlight” que podeis comprar aquí: http://www.campusmvp.com/Catalogo/Product-Windows-Phone-7.5-Mango—Desarrollo-Silverlight_142.aspx

El libro explica de forma precisa todos los aspectos que envuelven al desarrollo de aplicaciones para Windows Phone Mango con claros ejemplos (todos adjuntados en forma de proyectos para Visual Studio que podemos compilar y probar directamente en nuestro emulador!).

¡Sin duda una gran compra 100% recomendable!

 

Por otro lado, otro proyecto al que no podemos quitarle el ojo de encima es el recién estrenado PodCast sobre desarrollo en Windows Phone: Windows Phone Controla del omnipresente Josue Yeray y Rafael Serna.

 
Mensualmente nos traerán las noticias más destacadas dentro del mundo del desarrollo en Windows Phone así como explicar una API dentro del framework (por ejemplo, en este primer podcast explican el API del Live Connect!!)

Lo dicho, un proyecto más que interesante que promete ser una fuente de información y conocimiento cómoda, accesible y frecuente y es que, ¿Quien no querría sentarse en un bar a tomar una cerveza con dos grandes de Windows Phone como son Yeray y Serna?

 

¡A programar!

Con esto termino mi pequeña ruta de viaje dentro del mundo de Windows Phone. Espero que estos consejos os sean útiles a la hora de empezar con vuestra primera aplicación para el Marketplace y recordad que, si tenéis cualquier duda estamos en los foros de la MSDN para resolverla.

 

Un saludo y nos vemos compilando!!

TDD: Un ejemplo práctico sobre como mejorar la calidad de tu código

 

Ultimamente se habla mucho de diseño ágil pero la realidad de muchas empresas de desarrollo dista mucho de implementarlo de forma eficiente o directamente de usarlo en cualquiera de sus aspectos

Y es que el agilismo es una metodología muy fácil de entender pero costosa de poner en práctica si no se hace de la manera adecuada.

Por ese mismo motivo he visto que sería interesante dedicar una entrada a explicar de forma práctica y sencilla qué es TDD y cómo se utiliza en un proyecto.

 

Lo primero de todo confesar que no soy un experto en la materia y por ello es de obligada necesidad indicar que, si quereis profundizar más en estos temas, vayais a la web www.dirigidoportests.com de Carlos Blé, autor de “Diseño Ágil con TDD” el libro de cabecera de todo aquel desarrollador que quiera empezar a trabajar con esta metodología.

Además dar las gracias encarecidamente a Javier Casal por darme las clases magistrales de TDD y la gente de 12Meses12Katas por el ejemplo práctico para compartir con todos vosotros :)

 

¿Qué es TDD (Test Driven Development)?

El diseño dirigido por test, o TDD, es una técnica de diseño e implementación de software consistente en generar las pruebas unitarias justas y necesarias para obtener la implementación de las funciones que el cliente necesita minimizando los errores que llegan a producción.

El diseño por test no solo nos ahorra implementar más de lo debido si no que nos informa de si un cambio posterior “rompe” algo de lo que ya hemos implementado y nos facilita la tarea de entregar un código más limpio y libre de errores.

TDD no se trata de escribir cientos y cientos de pruebas si no se escribir las que necesites (y cuanto más simples mejor) para cumplir las necesidades del cliente y poder, posteriormente, empezar a desarrollar para cumplir dichos requisitos.

 

Como indico en el título esto es un ejemplo práctico sobre como utilizar TDD para resolver un problema concreto por lo que he hecho uso del problema de Noviembre del 2011 de 12Meses12Katas para ilustrar este post: KataPotter

Para ello vamos a crear una biblioteca de clases C# en Visual Studio 2010 y usaremos el framework de pruebas NUnit.

 

Explicando el problema

Bien, el problema que se nos plantea es la creación de un programa que calcule el importe de una coleción de libros aplicando un determinado descuento en función de los distintos tipos de libros que compremos. Partiendo de que cada libro tiene un coste de 8€ el cliente nos indica que, si se adquieren dos libros distintos, se aplique un 5% de descuento a ambos libros, un 10% si se compran 3, un 20% para 4 distintos y un 25% para la serie completa de 5 libros.

Otra condición del cliente es que el programa obtenga el precio más económico si hay varias combinaciones posibles de packs.

 

Como entrada recibiremos un array con los códigos de los libros a comprar (de 0 a 4) y como salida obtendremos un valor double.

¡Muy bien! Ya sabemos que tenemos que hacer y que quiere el cliente por lo que vamos a escribir las primeras pruebas.

 

Pruebas Sencillas

Lo primero que debemos hacer es escribir unas pruebas sencillas que implementen los casos más básicos. La primera y más sencilla es que cuando nuestra cesta de compra esté vacia el precio total es 0. En NUnit sería así:

[Test]
public void EmptyBasket()
{
     Assert.AreEqual(0, _bookPriceCalculator.CalculateBasket(new int[] { }));
}

Sin entrar en explicar la sintaxis de NUnit simplemente indicar que esta prueba comprueba que si se le pasa un array vacio el sistema devuelve 0.

¿Cómo resolvemos esta prueba con la menor cantidad de código posible? Muy fácil:

public double CalculateBasket(int[] books)
{
     return 0;
}

¡Exacto! Esa es la solución más sencilla que hace que la prueba sea correcta. Obviamente en cuanto añadamos una segunda prueba tendremos que rehacer nuestro código pero de esto se trata TDD.

¡Ok! Vamos ha añadir una nueva prueba para indicar una nueva condición impuesta por el cliente: Cada libro vale 8€

[Test]
public void TwoSameBook()
{
     Assert.AreEqual(8 * 2, _bookPriceCalculator.CalculateBasket(new int[] { 0, 0 }));
}

En esta prueba indicamos que si se compran dos veces el libro “0” el precio total es de 16€. ¿Cómo modificamos nuestro método para que pase las dos pruebas?

public double CalculateBasket(int[] books)
{
     return books.Length * 8;
}

¡Vale! No es muy elegante pero solucionaría cualquier prueba que no implique un descuento por lo que podemos cerrar el capítulo de pruebas sencillas.

 

Añadiendo Funcionalidad: Calculando Descuentos

Nuestro cliente nos había puesto como premisa que, si se compraban dos o más libros distintos había que aplicar un descuento determinado por lo que vamos a crear una serie de pruebas de ejemplo que implementen esta funcionalidad:

[Test]
public void TwoDifferentBooks()
{
            Assert.AreEqual(8 * 2 * 0.95, _bookPriceCalculator.CalculateBasket(new int[] { 0, 1 }));
}

[Test]
public void SeveralDiscountsTwo_One()
{
            Assert.AreEqual(8 + (8 * 2 * 0.95), _bookPriceCalculator.CalculateBasket(new int[] { 0, 0, 1 }));
}

Como veis en las pruebas tan solo declaramos una entrada de datos y la solución que nuestro cliente espera. Es trabajo del desarrollador el encontrar el modo en que el código del programa satisfaga todas las nuevas pruebas sin “romper” ninguna de las anteriores ya implementadas.

La solución que se me ha ocurrido a mi es hacer una clase “BookPack” que simbolice un “paquete de libros” donde todos los libros deben de ser distintos por lo que cada compra se traduce realmente en varios “BookPacks” cada uno con su precio y descuento.

Sin tener en cuenta la última condición (que indicaba que se ha de escoger la combinación más económica), la solución más sencilla es esta:

List<BookPack> BookPacks = new List<BookPack>();

foreach (int bookCode in books)
{
     BookPack currentBookPack = null;
     
     foreach (var bookPack in BookPacks)
     {
          if (!bookPack.HasThisBook(bookCode))
          {
              currentBookPack = bookPack;          
          }
     }

     if (currentBookPack == null)
            {
                BookPacks.Add(new BookPack(bookCode));
            }
            else
            {
                currentBookPack .Books.Add(bookCode);
            }
}
return BookPacks.Sum(bookPack => BookPack.GetBookPackPrice(bookPack.Books.Count));

Donde “GetBookPackPrice” devuelve el precio del paquete en función de cuantos libros tiene:

public static double GetBookPackPrice(int quantity)
        {
            return 8 * quantity * GetDiscountPerDifferentBooks(quantity);
        }
//GetDiscountPerDifferentBooks devuelve 1, 0.95, 0.9, 0.8 o 0.75 en función de si se compran 1, 2, 3, 4 o 5 libros distintos respectivamente.

Con esto ya tenemos implementada tanto la funcionalidad básica (ningún libro o varios libros iguales) como el descuento básico por “paquetes de libros”. Sólo nos faltaría añadir la última condición del cliente: que se elija la combinación más económica a la hora de hacer los paquetes.

 

Pruebas Finales: Obteniendo el paquete más económico

No es lo mismo hacer dos paquetes de 4 libros (51.2€ en total) que 1 de 5 y otro de 3 (51.6€). Con el código anterior obtendríamos la opción más desfavorable ya que solo se crea un nuevo paquete cuando el libro actual ya se encuentra en el paquete actual y no se tiene en cuenta el importe final.

Para añadir esta nueva funcionalidad vamos a escribir la última prueba:

[Test]
        public void SeveralDiscountsFourFour()
        {
            Assert.AreEqual(2 * (8 * 4 * 0.8), _bookPriceCalculator.CalculateBasket(new int[] { 0, 0, 1, 1, 2, 2, 3, 4 }));
        }

La implementación para este caso consiste en cambiar el concepto “CurrentBookPack” que tan solo va rellenando paquetes por “CheapestBookPack” el cual compara entre los distintos paquetes y se queda con el más económico.

Como el código resultante ya es más largo y enrevesado como para ponerlo en un post mejor lo veis directamente en mi repositorio de GitHub para este ejemplo ;-):

https://github.com/vfportero/Noviembre-KataPotter/tree/master/vfportero

 

Conclusiones Finales

Creo que este es un gran ejemplo para explicar las virtudes de TDD ya que en un mismo proyecto hemos tenido que hacer 3 modificaciones que han alterado por completo el funcionamiento de la aplicación

Al principio solo teníamos que calcular importes sencillos (8 * unidades), después se añadió unos descuentos por volumen para terminar con un sistema más inteligente que se queda con la combinación más económica.

Ahora extrapola este ejemplo a un proyecto real con cientos de clases y miles de líneas y piensa que pasaría si tuvieras que hacer este tipo de cambios… asusta, ¿verdad?

Y es que ¿cuantas veces hemos “arreglado algo y roto otro cosa”? ¿cuantas veces los requerimientos del software cambian y debemos adaptarnos rapidamente a las nuevas necesidades? ¿cuantas veces programamos más de lo debido?

 

TDD ayuda a solucionar estos problemas facilitandote el modo en el que organizas tus tareas. Cuando programas primero una prueba estás abstrayendote de algoritmos y estrategias para centrarte en entender el problema y la solución exacta que quiere el cliente.

Si logras crear pruebas simples que explican una pequeña parte del código podrás tener un sistema casi perfecto cuando el producto se entregue además de ganar en flexibilidad en caso de los requerimientos cambien en medio del desarrollo.

 

Está claro que escribir pruebas antes de programar es un trabajo extra que en muchos casos no se puede asumir pero, a la larga, ahorra mucho tiempo en mantenimiento y evita problemas de código heredado.

 

TDD, como otras herramientas dentro del agilismo, solo te da una serie de “buenas practicas” que te ayudan a mejorar tu calidad como desarrollador. Está en tu mano decidir hasta que punto utilizar TDD :-)

 

Para terminar solo invitar a todos aquellos interesados en este tema a que se pasen por la web de 12Meses12Katas donde encontraran ejemplos y soluciones a problemas como este “KataPotter” que hemos explicado aquí. Os recomiendo que os junteis con ese amigo programador con el que siempre haceis el friki, compreis una caja de cervezas, y empeceis a trabajar con una de estas Katas en parejas.

Mientras uno programa una prueba el otro programa el código que la implementa y viceversa. Vereis como TDD se ve de otra manera 😉

 

¡Nos vemos Compilando!

Configurar Réplica Maestro – Esclavo en MySql Server

 

Sé que este artículo se aleja un poco de lo que suelo escribir por aquí pero la clase magistral que me ha dado mi gran amigo Pedro Sanz sobre MySql bien se merece una entrada en el blog :-)

 

Hoy hemos tenido que montar para un cliente un servidor de réplica de MySql en el que era imperioso que los datos se espejeran de forma inmediata entre el servidor maestro y el esclavo.

Una réplica de MySql Server hace uso del fichero binario de transacciones para almacenar en el maestro todos los cambios reaizados (UPDATES, DELETES, CREATE, etc..) para que un servidor externo lo lea y replique exactamente los mismos cambios en su propia base de datos.

De este modo tenemos uno o más servidores MySql esclavos haciendo las mismas transacciones que el maestro para así tener los mismos datos en diferentes servidores cosa que se realmente útil y, no sólo ante caídas, ya que es posible configurar nuestra aplicación para compartir las SELECT entre distintos nodos de MySql y mejorar así el rendimiento.

 

Bueno, menos teoría y vamos al lío!.

Lo primero que debemos hacer es configurar el servidor maestro para que almacene el log binario y asignarle un identificador. Para ello editamos el my.cnf añadiendo (o editando si ya las tiene) las siguientes entradas:

#Identificador único del servidor maestro
server-id=1
#Nombre del fichero binario donde se almacenarán las transacciones
log-bin=mysql-bin
sync_binlog=1
#Tamaño del fichero de log tras lo que se truncara
max-binlog-size=500M
expire_logs_days=4
innodb_flush_log_at_trx_commit=1

Como siempre que modificamos un my.cnf hay que reiniciar el servicio de MySql para que acepte los cambios.

Luego tenemos que hacer lo propio con el (o los) esclavo(s). Modificar el my.cnf con los siguientes parámetros y luego reiniciar el servicio:

#Indentificador único del esclavo
server-id=2
relay-log=mysqld-relay-bin
max-relay-log-size=500M
relay_log_purge=1

¡Muy bien! Ya tenemos un servidor maestro y un esclavo pero ahora necesitamos crear un usuario para que el esclavo se conecte al maestro y pueda leer el log de transacciones. Para ello vamos a crear un nuevo usuario llamado “replicador” (el nombre y pass puede variar, jeje) en el master con privilegios de “REPLICATION SLAVE“:

CREATE USER replicador IDENTIFIED BY 'elpassword';

Y luego le damos los permisos de REPLICATION SLAVE:

GRANT REPLICATION SLAVE ON *.* TO 'replicador'@'%' IDENTIFIED BY 'elpassword';
FLUSH PRIVILEGES;

Ok! Ya tenemos los servidores bien configurados y el usuario que usaremos como replicador por lo que lo próximo que tenemos que hacer es crear una copia inicial o “snapshot” de la base de datos que queremos replicar para luego poder indicar al servidor esclavo desde dónde tiene que empezar a leer.

Para hacer el snapshot primero ejecutamos las siguientes consultas:

FLUSH TABLES;
FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;

Ten en cuenta que al hacer “READ LOCK” estamos bloqueando la tabla para que nadie cambie nada por lo que lo que viene a continuación deberíamos hacerlo lo más rápidamente posible.

El SHOW MASTER STATUS muestra dos valores que debemos anotar que son el “File” y “Position“. Necesitaremos indicarselos al servidor de réplica una vez hayamos cargado la copia inicial.

+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |     492 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

¡Muy bien! Vamos al servidor esclavo y lo terminamos de configurar.

Lo primero es cargar una copia de seguridad de base de datos que queremos replicar del master al esclavo (puedes usar el método que quieras, mysqldump, HeidSql, MySql Workbench…) y, una vez restaurada, configurar el esclavo e iniciarlo.

En este ejemplo vamos a suponer que el servidor maestro está alojado en 10.0.1.10. Fíjate que tenemos que indicar el File y la Position que hemos obtenido antes del SHOW MASTER STATUS:

CHANGE MASTER TO MASTER_HOST='10.0.1.10', MASTER_USER='replicador', MASTER_PASSWORD='elpassword', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=492, MASTER_PORT=3306;

START SLAVE;

Para terminar volvemos al maestro y desbloqueamos de nuevo las tablas para que puedan volver a editar datos:

UNLOCK TABLES;

¡Ya está! Si no ha pasado nada raro tendremos el servidor esclavo con la carga inicial funcionando y todo cambio en el master se replicara por arte de magia.

Si queremos saber el estado del servidor de réplica podemos usar la consulta:

SHOW SLAVE STATUS\G

Que nos mostrará un listado de datos. Yo miro el valor “Seconds_Behind_Master” que indica que “retraso” tiene el servidor esclavo respecto al maestro (si es NULL es que no va. Revisa el “Slave_IO_State” y “Last_Error”).

Ahora empieza a meter datos en la base de datos maestra y verás como ellos solitos aparecen en la esclava… ¡brujería! :-)

 

Espero que esto os sea útil.

Nos vemos Compilando!!

Trasteando con Windows 8, Visual Studio 11 y .NET 4.5: Mi primera aplicación Metro

 

La pasada semana sufrimos un aluvión de noticias relacionadas con la presentación de la nueva criatura de Microsoft: Windows 8.

Windows 8

Con una renovada Interfaz llamada “Metro“, Windows 8 promete revolucionar el mercado de los operativos ofrenciendo un sistema multiplataforma capaz de ser ejecutado desde el sobremesa más potente hasta la tablet más económica.

 

Pero este post no va sobre que es Metro, Windows 8 o que trae de nuevo el Internet Explorer 10; vamos a hablar de lo que realmente nos interesa:

  • ¿Qué trae el nuevo Visual Studio 11 y su .NET 4.5?
  • ¿Cómo se desarrolla con Metro?
  • ¿Qué son y cómo funcionan los nuevo métodos asíncronos?
 

Visual Studio 11: Creando un proyecto Metro

En la beta del VS 11 nos vienen por defecto varios tipos de plantillas de aplicaciones: Metro, Grid y Split. En este caso vamos a usar la plantilla por defecto “Metro” para hacer una aplicación Metro de ejemplo con el listado en tiempo real de post de este blog y su contenido como detalle.

 

Lo primero que nos llama la atención es que la interfaz está completamente en WPF (Windows Presentation Foundation) así que solo tenemos una página .xaml y su correspondiente .cs. 

Ok, no nos asustemos, es algo distinto a lo que estamos acostumbrados pero no pasa nada. El objetivo de este ejemplo es conseguir una aplicación que liste el contenido del feed de esta web en un ListView y que cuando pulsemos en un post cargue el html de dicho post en el cuerpo de la aplicación.

Vamos a empezar primero por crear la clase FeedData que almacenará los datos leídos para luego obtener de forma asíncrona el valor del feed directamente de la url: http://www.compilando.es/syndication.axd

 

C# 5 y Windows.Web.Syndication: Obtener datos del Feed Rss

Bien, vamos a bindear una lista de “items” rss que tendrán las propiedades de Título, Fecha, Autor y Contenido. Lo primero es crearnos la clase que usaremos para bindear con el futuro control y nos creamos también una coleccion de tipo “ObservableCollection” para que el xaml pueda bindearlo correctamente.

El código como veis es muy simple:

public class FeedData
    {
        public string Titulo { get; set; }

        private ObservableCollection<FeedItem> _Items = new ObservableCollection<FeedItem>();
        public ObservableCollection<FeedItem> Items
        {
            get
            {
                return this._Items;
            }
        }
    }

    public class FeedItem
    {
        public string Titulo { get; set; }
        public string Autor { get; set; }
        public string Contenido { get; set; }
        public DateTime Fecha { get; set; }

    }

 

Una vez creada la clase vamos al meollo del asunto que es como leed del feed, bajarse los datos y crear los correspondientes “FeedItems”. Actualmente tenemos que usar XmlReaders y métodos más o menos manuales para leer un feed rss.

Con .NET 4.5 tenemos una multitud de clases nuevas que nos ofrecen funcionalidades no existentes hasta ahora como Windows.Web.Syndication que nos da una serie de clase y métodos para tratar con feed’s rss así como la posibilidad de ejecutarlo de forma asíncrona.

¡Al grano! Necesitamos un método que se ejecute al iniciar la aplicación, que lea del feed y bindee el resultado en el “DataContext” de la página. Como queremos que la aplicación no se quede “frita” mientras baja el feed vamos a hacer uso de los métodos asíncronos para invocar el método.

Como vale más código que mil palabras os lo pego y lo voy comentado inline 😉

// Hay que firmar el método como "async" y "Task" para que el compilador cree un hilo para el solo y podamos hacer uso de las herramientas asíncronas
        private async Task ObtenerFeedAsincronamente(string feedUrl)
        {
            // using Windows.Web.Syndication;
            // SyndicationClient -> Clase para trabajar con Feed's RSS
            SyndicationClient client = new SyndicationClient();
            Uri feedUri = new Uri(feedUrl);

           
                //Obtenemos el feed de la URL dada y esperamos a que termine añadiendo la palabra clave "await" 
                SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri);

                // Ya tenemos en "feed" todos los datos necesarios. Sólo tenemos que recorrerlo y crear las clases para el bindeo
                FeedData feedData = new FeedData();
                feedData.Titulo = feed.Title.Text;

                foreach (SyndicationItem item in feed.Items)
                {
                    FeedItem feedItem = new FeedItem();
                    feedItem.Titulo = item.Title.Text;
                    feedItem.Fecha = item.PublishedDate.DateTime;
                    feedItem.Autor = item.Authors[0].Name;
                    if (feed.SourceFormat == SyndicationFormat.Atom10)
                    {
                        feedItem.Contenido = item.Content.Text;
                    }
                    else if (feed.SourceFormat == SyndicationFormat.Rss20)
                    {
                        feedItem.Contenido = item.Summary.Text;
                    }
                    feedData.Items.Add(feedItem);
                }
                // Bindeamos el ObservableCollection<FeedItem> y seleccionamos el primero
                this.DataContext = feedData;
                ItemListView.SelectedIndex = 0;
            
        }

 

¡Así de fácil! Basta con poner “async” como firma del método y “await” en el momento que queremos que se pare la ejecución de este método para que el compilador salte fuera del método, siga su ejecución y escuchando eventos y, cuando termine la llamada “await” vuelva a la siguiente linea y siga ejecutandose. Con esto conseguimos que el usuario pueda seguir trabajando con la aplicación mientras la aplicación trabaja por debajo.

Bien, ya hemos obtenido los datos pero, ¿cómo los muestro en mi interfaz?

¡Vamos a por el WPF!

 

Controles WPF: Bindeo de Datos en Metro UI

En nuestro MainPage.xaml por defecto veremos un “Grid” ya creado que es la rejilla en la que vamos a crear los controles. Como queremos hacer una aplicación Metro bien chula como las que se ven en los videos de presentación de Windows 8 vamos a montar una interfaz con una cabecera, una lista de artículos en un lateral usando 2/5 de la pantalla y su contenido en el centro ocupando los 3/5 restantes.

Bien, con estas premisas necesitamos hacer uso de dos controles: ListView y WebView.

Un ListView es muy muy parecido a lo que hemos visto toda la vida: un control que repite ciertos elementos una vez por cada item

WebView es un control que interpreta HTML como si de un navegador se tratará lo cual nos viene de perlas para mostrar el contenido del post que previamente hemos leído.

Como antes os comento entre líneas. Ojo a cómo se bindea el Grid que contiene el cuerpo del post que parece magia :)

 

<Grid x:Name="LayoutRoot" Background="#FF0C0C0C">
        <!-- Definimos 2 lineas. Una de 140px para el título y la siguiente que llegue hasta el final-->
        <Grid.RowDefinitions>
            <RowDefinition Height="140" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <!-- Titulo. Corresponde con la primera "row" de 140px -->
        <TextBlock x:Name="TitleText" Text="Compilando.ES RSS FEED"
                   VerticalAlignment="Center" FontSize="48" Margin="56,0,0,0"/>

        <!-- Cuerpo. Como veis indicamos que es la row "1" por lo que debe usar el resto de la pantalla -->
        <Grid Grid.Row="1">
            <!--Definimos dentro del Grid principal otro Grid secundario dividido en 5 partes con dos columnas.-->
            <!--La primera tendrá un ancho mínimo de 320px y usará 2/5 partes del espacio total-->
            <!--La segunda usará 3/5 parte del ancho total del Grid-->
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="2*" MinWidth="320" />
                <ColumnDefinition Width="3*" />
            </Grid.ColumnDefinitions>

            <!-- Listado de Post -->
            <!-- Indicamos que utilice el ObservableCollection<FeedItem> llamado Items del DataContext de la página -->
            <ListView x:Name="ItemListView"  
                      ItemsSource="{Binding Path=Items}"
                      SelectionChanged="ItemListView_SelectionChanged"
                      Margin="60,0,0,10">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <!-- Controles que se repetirán una vez por cada Item en "Items" -->
                        <!-- Usamos un StackPanel con 3 TextBlock bindeados -->
                        <StackPanel>
                            <TextBlock Text="{Binding Path=Titulo}"  
                                       FontSize="24" Margin="5,0,0,0" TextWrapping="Wrap" />
                            <TextBlock Text="{Binding Path=Autor}" 
                                       FontSize="16" Margin="15,0,0,0"/>
                            <TextBlock Text="{Binding Path=Fecha}" 
                                       FontSize="16" Margin="15,0,0,0"/>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

            <!-- Cuerpo del Post -->
            <!-- Se bindea en función del elemento seleccionado del ItemListView -->
            <Grid DataContext="{Binding ElementName=ItemListView, Path=SelectedItem}"
                  Grid.Column="1" Margin="25,0,0,0">
                <!-- Como antes le decimos que tiene 2 filas. La primera será un TextBlock con el título del Post y la segunda el control WebView que mostrará el contenido del post -->
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <TextBlock Text="{Binding Path=Titulo}" FontSize="24"/>
                <WebView x:Name="ContentView" Grid.Row="1" Margin="0,5,20,20"/>
            </Grid>
        </Grid>
    </Grid>

 

¡Casi casi lo tenemos! Como veis en los comentarios el Grid “Cuerpo” se bindea en función del elemento seleccionado del ItemListView (lo que nos ahorra bastante código) pero ¿cómo cargamos el contenido HTML dentro del WebView?

Bueno, nos toca usar el evento “ItemListView_SelectionChanged” del ListView para ello:

private void ItemListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            FeedItem feedItem = (sender as ListView).SelectedItem as FeedItem;
            if (feedItem != null)
            {
                // Si tiene contenido simplemente se lo "encasquetamos" al WebView y el solito interpreta el HTML como si fuera un navegador.
                ContentView.NavigateToString(feedItem.Contenido);
            }
        }

 

¡Ya está! Tenemos nuestra primera aplicación Metro que encima es útil y hasta bonita!!

 

Conclusiones

Las nuevas mejoras de C# 5 sobre sincronía son fantásticas ya que nos permite mover el flujo de la aplicación como queramos de forma muy sencilla aunque quizá haya que aprender bien a como y cuando usarlas y sobre la interfaz Metro que decir… yo estoy  enamorado. Decían que Microsoft tenía mal gusto… Quien rie el último… jeje 😉

 

No voy a entrar en polémicas sobre si se llevará un batacazo o no, sobre si la gente sabrá usar la nueva interfaz o si se perderá en el intento, si Windows se ha reinventado a si mismo… sólo sé que este movimiento de Microsoft facilitando las herramientas de desarrollo con tanto tiempo de antelación de manera gratuita para que todos las probemos no es una casualidad. Cuando tengamos Windows 8 entre nuestras manos ya habrán cientos de apps listas para ser usadas e incluidas en al Windows Store que funcionarán tanto en Windows 8 como en Windows Phone y yo, por mi parte, no pienso perder la oportunidad de seguir trabajando con esta tecnología :-)

 

Por si alguien tiene la beta y quiere trastear con mi código os dejo el ZIP con la solución completa!

Compilando_ES_Metro_Example.zip (111,39 kb)

 

¡Nos vemos Compilando!