dilluns, 9 de setembre de 2013

TDD estan molt bé però...

Doncs com ja heu vist (si és que algú segueix el meu bloc, clar ;)) que estic intentant aprendre a programar decentment. I intente, per això, gastar TDDs. Però de vegades em planteja més problemes propis del sistema de test, que si no els gastara.
L'exemple que m'ha fet "pedre" unes quantes hores, és amb el nunit de Visual Studio, fent un test d'una classe em C# de Windows Phone Class Library (target 7.1 SDK, no sé si això és rellevant però pense que no). En resum, el test seria algo així:

   [TestMethod]
        public void testAutenticadorLogin()
        {
            Autenticador au = new Autenticador("http://localhost", 800, "test", "test");
            au.login();
        }

Què simplement intenta autenticar mitjançant un webservice instal·lat en localhost, l'usuari test i la contrassenya test.

Doncs sempre que intentava llançar el test em traia una excepció d'arxiu no trobat. Després de diverses proves, inclús funcionant en l'aplicació de mostra però no en el test, descubrisc què el problema està en al fer el login (au.login), per tal d'obrir una url remota (l'accés al webservice) gastem el el component WebClient:

 System.Net.WebClient wc = new System.Net.WebClient();

Si comentava eixa línia el programa no fallava al runtime (òbviament no feia l'esperat). Pareix ser què al ser una dependència (System.Net) no la pot trobar el sistema de test (nunit). L'única solució que he trobat després de fer un poc de googling ha segut anar a C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0 (la carpeta on està instal·lat el framwork utilitzat) i copiar tant el .xml com el dll corresponent a System.net a la carpeta debug del projecte de test:

  1. Anar a la carpeta on està el framework, en el meu cas C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0
  2. copiar els arxius .dll i .xml que creen la dependència, en el meu cas System.Net.dll i System.Net.xml, a la carpeta debug
  3. creuar els dits i que funcione ;)
El cas és que ara no llença l'excepció, però he de continuar mirant que passa per què ara a l'intentar descarregar la url (en el callback) dona este missatge:
[net_webclient]\r\nArgumentos: \r\nLas cadenas de recursos de depuración no están disponibles. La clave y los argumentos suelen proporcionar suficiente información para diagnosticar el problema. Vea http://go.microsoft.com/fwlink/?linkid=106663&Version=4.0.60310.0&File=System.Net.dll&Key=net_webclient

Ja que, entre altres coses eixa url no existeix ja ;)
I recorde, el problema només està en el framework de test, l'aplicació mòbil funciona "funciona" perfectament.

dijous, 5 de setembre de 2013

Múltiples plataformes amb Visual Studio II ( i Estrenant GitHub )

Ja fa temp que volia fer alguna cosa semblant. Ja fa temps vaig crear un parser C# per a feeds atom que val tant per Android, com per a WP ( i deuria de valer per a IOS també). Molt modest però valia per a fer aplicacions que llegiren de blogs personals. El parser formarà part de d'una col·lecció que aniré afegint anomenada (molt originalment) util, que es pot trobar en https://github.com/fercavi/util.

La classe anomenada cAtom (notació hongaresa, la vaig fer abans de llegir Clean Code ;)), només té una operació, Run() ;) (realment 2, ara ho explique).  Quan acabe el Run tindrà dos llistes, una de títols (getTitle) i una de notícies (getValue).
Els passos seran els següents:
1. Inicialitzar-la en el constructor, diguent-li la url que volem llegir i, opcionalment, el nombre d'elements que volem extraure (per defecte 10).
2. Afegir-li un callback, en els mòbils la majoria d'events són asíncrons, per tant necessitarem una funció de callback que serà la que carregue la informació gràfica d'interfície  una vegada estiga carregada la informació del feed Atom.
3. Executar Run() que serà el procés que faça la feina i quan acabe execute la funció callback del pas 2.


Anem a veure l'exemple d'ús per a Android i per a WP. Tenim el projecte WPCore  (WP Class Library) què tindrà el namespace util, ara només la classe cAtom. (ho he havut de fer així per com funciona Xamarin). I creem un projecte testWP (Windows Phone App) que tindrà la interfície gràfica i demés coses específiques de WP. A la interfície WP afegim un botó i un navegador web, per a visualitzar les dades baixades. El codi seria:

private void Button_Click_1(object sender, RoutedEventArgs e)
        {

            carregador = new util.cAtom("http://www.vicentfernandez.cat/feeds/posts/default", 10);
            carregador.CarregarDades += callBackCarregador;
            carregador.Run();
        }

Vegem que hem afegit un callback que serà qui òmpliga les dades:

private void callBackCarregador()
        {
            string html = "<html><body>";
            foreach (var titol in carregador.getTitle())
            {
                html += "<h2>" + titol + "</h2>";
            }
            html += "</body></html>";
            visualitzador.NavigateToString(html);
        }

I ara vegem el resultat:



Ara anem a fer la mateixa aplicació en android. Creem una Android Class Library (anomenada AndroidCore) buida i afegirem un element existent (cAtom.css) de l'anterior projecte. Però hem de tindre en compte que haurem de posar afegir com a link enlloc de copiar, per tal que les modificacions en un projecte afecten a l'altre.
Després crearem un altre projecte Android (anomenat testAndroid), però esta vegada aplicació, i afegirem una referència a l'anterior projecte. Afegim un WebView a l'aplicació i posem el codi per a què quan s'aprete el botó es visualitze:

 button.Click += delegate
            {
                carregador = new util.cAtom("http://www.vicentfernandez.cat/feeds/posts/default", 10);
                carregador.CarregarDades += CallbackCarregarDades;
                carregador.Run();
            };

Vegem que (òbviament) també té un callback:
private void CallbackCarregarDades()
        {
             Android.Webkit.WebView wc = FindViewById<Android.Webkit.WebView>(Resource.Id.webView1);
             string html = "<html><body>";
             foreach (var titol in carregador.getTitle())
             {
                 html += "<h2>" + titol + "</h2>";
             }
             html += "</body></html>";
             wc.LoadData(html, "text/html; charset=UTF-8", "ISO-8859-1");
       }

I ara vegem el resultat: