Tutorial MVVM IV

Continuando con el Tutorial de MVVM, creamos un proyecto de Test unitarios, para que verifique el comportamiento de los métodos que hemos incluido en el modelo.

Por organizar un poco el proyecto de test, creamos una carpeta llamada Model, a la que le introducimos una clase llamada ClientTest.cs. Esta clase, verifica lo métodos de la clase Client, los parámetros que recibe y los resultados que arroja:

  • GetLocations(String query, int maxResults). Este método debe devolver un listado de la clase Location, el cual no puede ser nulo y los parámetros de entrada no pueden ser nulos, y en el caso de maxResults, debe ser un entero en un intervalo entre 0 y 20.
  • GetWeather(Coordinates coords). Debe devolver un objeto Weather, el cuál no puede ser nulo, y el parámetro de entrada nunca debe llegar nulo.

Para ello debemos referenciar, el proyecto del Modelo en el proyecto de Test, y luego en la clase debemos agregar un Using referenciando al modelo dentro de la clase.

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WeatherApp.Model;

namespace WeatherApp.Test.Model
{
    [TestClass]
    public class ClientTest
    {
        [TestMethod]
        public void GetLocations()
        {
            var query = String.Empty;
            var maxResults = -1;
            var list = Client.GetLocations(query, maxResults);
            Assert.AreEqual(list, null);
            query = "Madrid";
            maxResults = new Random().Next(0, 20);
            list = Client.GetLocations(query, maxResults);
            Assert.IsTrue(list != null && list.Count >= 0);
        }

        [TestMethod]
        public void GetWeather()
        {
            var coords = new Coordinates
                             {
                                 Latitude = 0D,
                                 Longitude = 0D
                             };
            var weather = Client.GetWeather(null);
            Assert.IsNull(weather);
            weather = Client.GetWeather(coords);
            Assert.IsNotNull(weather);
        }
    }
}

Una vez elaborado el test, programamos la clase Client del Modelo, y nos queda algo así:

using System;</pre>
<pre>using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Xml.Linq;

namespace WeatherApp.Model
{
    public static class Client
    {
        private static readonly CultureInfo Culture = new CultureInfo("EN-US");

        public static List<Location> GetLocations(String query, int maxResults = 20)
        {
            if (String.IsNullOrEmpty(query) ||
                !(maxResults > 0 && maxResults <= 20)) return null;

            var url = String.Format(Properties.Resources.UrlBing, 
                                    query,
                                    maxResults, 
                                    Properties.Resources.KeyBing);

            List<Location> list;
            try
            {
                var doc = XDocument.Load(url);
                var locs = from q in doc.Descendants()
                            .Where(q => q.Name.LocalName == "Location")
                            select new
                           {
                               Name = q.Descendants()
                                   .Where(r => r.Name.LocalName == "Address")
                                   .Elements()
                                   .First(s => s.Name.LocalName == "Locality")
                                   .Value,
                               Country = q.Descendants()
                                   .Where(r => r.Name.LocalName == "Address")
                                   .Elements()
                                   .First(s => s.Name.LocalName == "CountryRegion")
                                   .Value,
                               Latitude = q.Descendants()
                                   .Where(r => r.Name.LocalName == "Point")
                                   .Elements()
                                   .First(s => s.Name.LocalName == "Latitude")
                                   .Value,
                               Longitude = q.Descendants()
                                   .Where(r => r.Name.LocalName == "Point")
                                   .Elements()
                                   .First(s => s.Name.LocalName == "Longitude")
                                   .Value,
                           };

                list = locs.Select(q => new Location
                {
                    Name = q.Name,
                    Country = q.Country,
                    Coordinates = new Coordinates
                    {
                        Latitude = Convert.ToDouble(q.Latitude, Culture),
                        Longitude = Convert.ToDouble(q.Longitude, Culture)
                    }
                }).ToList();
            }
            catch (Exception)
            {
                list = null;
            }
            return list;
        }

        public static Weather GetWeather(Coordinates coords)
        {
            if (coords == null) return null;

            var url = String.Format(Properties.Resources.UrlAPI, 
                                    Properties.Resources.KeyAPI,
                                    coords.Latitude.ToString(Culture), 
                                    coords.Longitude.ToString(Culture));
            Weather weather = null;
            try
            {
                var dser = new DataContractJsonSerializer(typeof(Weather));
                var req = WebRequest.Create(url);

                using (var s = req.GetResponse().GetResponseStream())
                {
                    if (s != null)
                    {
                        weather = (Weather)dser.ReadObject(s);
                    }
                }
            }
            catch (Exception)
            {
                weather = null;
            }
            return weather;
        }
    }
}</pre>
<pre>

En el siguiente capítulo empezaremos a trabajar con la vista, a agregar controles al proyecto de WPF.