Aprendiendo .NET sobre la marcha


Aprendiendo .NET sobre la marcha (ii)>>

En Visual Studio hay una gran cantidad de plantillas para diferentes proyectos, según lo que requieras realizar. Para esta serie de publicaciones comenzaré con una aplicación de consola, que es de lo más básico y ya casi nadie quiere utilizar, puesto que es en modo texto y a los usuarios les gusta lo gráfico, sin embargo, este tipo de aplicaciones es el mejor para ejecutarse en servidores y aplicaciones críticas, donde lo primordial es el rendimiento.

Dicho sea de paso: iré utilizando otro tipo de proyecto disponible en VS para realizar las pruebas de cada proyecto. ¿Por qué? Porque a lo largo de mi actividad como desarrollador, gran parte del tiempo lo consumo realizando pruebas, y ya que VS provee de un motor con esta finalidad y un tipo de proyecto específico, pues a darle uso. Igualmente, conceptos fundamentales los iré desglosando sobre la marcha, para darle un caracter más dinámico al asunto. Por cierto, mis ejemplos se basan en matemáticas, ya que son suficientemente abstractas, dinámicas, transformables y clasificables para comprender ciertos aspectos de la Programación (finalmente el software es intangible y abstracto pero se puede transformar en algo concreto).

Abriendo VStudio, en el menú archivo o en la página de inicio buscamos la opción para crear un nuevo proyecto. De entre las opciones que nos presenta, buscamos en la parte izquierda Escritorio de Windows y a la derecha Aplicación de Consola y luego de poner un nombre (yo dejaré el que viene por defecto), damos clic en Aceptar.

El código generado es similar al siguiente:

using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;

  namespace ConsoleApp1 {
    class Program {
      static void Main(string[] args) {
      }
    }
  }
    

La primera parte es una lista de using, esto quiere decir que tendremos a nuestra disposición las clases contenidas en System, System.Collections.Generic y los demás de la lista. Cada uno de esos nombres es un Espacio de Nombres y son la forma en que se agrupan las clases en .NET, de igual forma, nosotros estaremos creando un espacio de nombres llamado (en mi caso) ConsoleApp1. ¿Por qué hay espacios de nombres con puntos? Porque están agrupando más espacios de nombres dentro de sí, por ejemplo, System contiene funciones del sistema y a su vez también contiene al espacio Collections que refiere al manejo de colecciones de datos (más adelante lo veremos), de igual forma, este último espacio contiene al espacio Generic. Nosotros podemos hacer lo mismo con nuestras clases.

De hecho, la clase Program está contenida en nuestro espacio de nombres.

Si observamos, contiene una instrucción: static void Main(string[] args). Este es el punto de partida para nuestra aplicación de consola, y aquí comienza la magia.

static void Main(string[] args) {
    int a = 1, b = 2, c = 0;
    c = a * b;
    Console.WriteLine(string.Format("{0} * {1} = {2}",a, b, c));
    Console.ReadLine();
  }
    

Console es una clase que está definida dentro de System, y tiene métodos que nos permiten trabajar con la consola del sistema. Los métodos que estamos utilizando son llamados estáticos, esto queire decir que pueden ser utilizados directamente desde la clase que los contiene. string es, además de un tipo de dato, una clase con una cantidad de métodos interesantes para trabajar con cadenas de caracteres (en realidad, todos los tipos de datos en .NET son clases). El método Format permite crear una cadena formateada pasándole además, una serie de parámetros, es similar a como en C/C++ se maneja la función "printf".

static void Main(string[] args) {
    int a = 1, b = 2, c = 0;
    c = a * b;
    string sa = string.Empty, sb = string.Empty;

    Console.Write("Primer número:");
    sa = Console.ReadLine();
    Console.Write("Segundo número:");
    sb = Console.ReadLine();

    int.TryParse(sa, out a);
    int.TryParse(sb, out b);

    Console.WriteLine(string.Format("{0} * {1} = {2}",a, b, c));
    Console.ReadLine();
  }
    

Agregamos algunas variables de tipo string y procedemos a solicitar al usuario los datos necesarios. La clase "int" posee un método estático llamado TryParse que realiza la conversión de una cadena (primer parámetro) y regresa en un int el resultado de la conversión (en caso de fallar, el valor entero devuelto es el mismo con el que inicializamos la variable). Observa que la palabra out se usa para decirle a .NET que ese parámetro es de salida (no utilizable en todos los casos, solo donde se haya definido un parámetro de salida).

Comencemos a ordenar nuestro código separándolo en métodos que reciban datos y regresen resultados. Entonces, un método es una función que puede ser utilizada por la clase, sus instancias y derivados, dependiendo de cómo se defina este método (protected, private, static, public). También entremos en terreno de las pruebas unitarias que nos serán muy útiles.

Lo primero será construir un método que reciba tres datos de tipo cadena y regrsará el resultado de una operación, de acuerdo con los argumentos.

La palabra static nos permite que el método sea utilizado sin necesidad de crear una instancia de la clase a la que pertenece, esto lo hacemos así en este caso porque no requerimos aún crear objetos y nos basta usar la definición de la clase como viene de inicio.

public static int Operando(string _a, string _b, string _o) {
    int r = 0;
    int a = 0, b = 0, c = 0;

    int.TryParse(_a, out a);
    int.TryParse(_b, out b);

    switch (_o) {
      case "suma":
        r = a + b;
        break;
      case "resta":
        r = a - b;
        break;
      case "multiplica":
        r = a * b;
        break;
      case "divide": // A propósito no estoy validando que b sea distinto de cero
        r = a / b;
        break;
    }
    return r;
  }
    

Lo siguiente es ajustar nuestro método inicial para que quede de la siguiente forma

static void Main(string[] args) {
            string sa = string.Empty, sb = string.Empty, so = string.Empty;
            int resultado = 0;
            Console.Write("Primer número:");
            sa = Console.ReadLine();
            Console.Write("Segundo número:");
            sb = Console.ReadLine();
            Console.Write("Operación (suma, resta, multiplica, divide): ");
            so = Console.ReadLine();

            resultado = Operando(sa, sb, so);

            Console.WriteLine(string.Format("{0} , {1} => {2}", sa, sb, resultado));
            Console.ReadLine();
        }
    

Ahora pediremos a VStudio que nos genere un nuevo proyecto de pruebas unitarias para los métodos que vayamos construyendo, con esto nos facilitaremos la vida un poquito al hacer que se ejecuten todas las pruebas que necesitemos de manera más rápida. Para ello, primero modificamos nuestra clase agregándole la palabra reservada public antes de class, luego damos clic con el botón secundario del mouse sobre el nombre del método, y del formulario que nos muestre, únicamente cambiamos la última opción eligiendo Cuerpo Vacío y damos en Aceptar para que genere el proyecto con la primera prueba unitaria.

Es mejor generar una prueba por cada posible caso para un mismo método y no agruparlas en una sola prueba, aunque esto es posible. La razón es que las pruebas, conforme agregamos complejidad y posibilidades a un método, rastrear todo desde una misma prueba se vuelve complejo.

VStudio generará una nueva aplicación de consola con la siguiente clase y su método vacío:

[TestClass()]
    public class ProgramTests
    {
        [TestMethod()]
        public void OperandoTest() {
        }
    }
    

El atributo [TestClass()] indica que se trata de una clase específica para realizar pruebas, mientras que [TestMethod()] indica que el método será usado para tal fin. Entonces, ya con nuestro primer método de pruebas procedemos a realizar algunos ajustes a la misma para que quede como sigue:

[TestMethod()]
        public void OperandoSumaTest() {
            int r = Program.Operando("1", "2", "suma");
            Assert.IsTrue(r == 3, "Error al realizar la suma");
        }
    

El cambio de nombre es para que sea más fácil identificar a qué refiere la prueba, el código es simple: la primera instrucción declara una variable de tipo entero que recibe el resultado de llamar el método estático Operando de la clase Program, le estámos proporcionando tres argumentos de tipo cadena: dos números y la operación que realizará. La segunda instrucción es la evaluación de la prueba. Assert es una clase que tiene métodos estáticos, de los cuales estamos usando IsTrue para determinar que, si es verdad la condición, entonces continúe, en caso contrario termina la ejecución de la prueba mostrando el mensaje de error que le indiquemos.

Aunque por el momento es suficiente que sepamos si la prueba fue exitosa o no, conforme nuestras pruebas sean más compleja, será importante tener un mensaje de respuesta si la prueba fue aprobatoria, para ello modificamos nuestra clase de la siguiente manera.

[TestClass()]
    public class ProgramTests
    {
        [TestMethod()]
        public void OperandoSumaTest() {
            int r = Program.Operando("1", "2", "suma");
            Assert.IsTrue(r == 3, "Error al realizar la suma");

            Console.WriteLine(string.Format("Operación {0} realizada correctamente. Resultado = {1}", "suma", r));
        }
    }

    

De esta forma el explorador de pruebas mostrará un enlace de salida que al darle clic mostrará en el panel principal el mensaje que hayamos indicado sea desplegado.

Finalmente, en nuetro método original damos clic con el botón secundario y elegimos Ejecutar pruebas unitarias, lo que iniciará el proceso de compilación y posterior ejecución de nuestra prueba, mostrando el resultado en el panel del Explorador de Pruebas

Hasta aquí dejo esta parte. En posteriores publicaciones seguiré explicando los aspectos de la programación en .NET modificando nuestra aplicación y agregándole funcionalidades, para luego pasar a otros tipos de proyectos procurando construir uno lo mejor estructurado posible desde un inicio, y explicando las ventajas de tal organización.

Agradezco los comentarios que puedan hacerme, así como el que se suscriban para recibir noticias y, si consideran útil, compartir mi blog.

Comentarios

Entradas populares