sábado, 26 de agosto de 2017

Crear un proyecto de pruebas con Visual Studio y Selenium


Saludos. Esta entrada es un tutorial acerca de cómo crear un proyecto de pruebas en Visual Studio utilizando Selenium (por si el título que dice casi lo mismo no es lo suficientemente claro - comentario sarcástico para mí mismo).

¿Qué es Selenium?

Selenium es un conjunto de herramientas de automatización para navegadores, que permite programar y ejecutar pruebas repetitivas para aplicaciones web.

Creación del proyecto y adición de Selenium

El tutorial se ha realizado utilizando Visual Studio Community Edition 2017, y C#. Los pasos para crear el proyecto y ejecutar una prueba de ejemplo se describen a continuación:

El primer paso es abrir Visual Studio, y crear un nuevo proyecto de pruebas unitarias, a través del menú Archivo > Nuevo > Proyecto, y seleccionando la plantilla Proyecto de Prueba Unitaria (.NET Framework), ubicada en las plantillas instaladas bajo la categoría Visual C# > Prueba.


Luego de ello, se procede a agregar los paquetes de Selenium en la solución. Para ello, se abre el panel del Explorador de soluciones, se da clic derecho sobre el proyecto, y se selecciona la opción Administrar paquetes NuGet.


Esto despliega en pantalla el administrador de paquetes NuGet para el proyecto seleccionado. En él se selecciona la opción Examinar, y se procede a realizar la búsqueda de paquetes con la palabra Selenium.


De la lista obtenida, procedemos a instalar los paquetes Selenium.WebDriver (publicado por Selenium Committers) y Selenium.Support (también publicado por Selenium Committers). Estos paquetes incluyen soporte para los navegadores Internet Explorer y Firefox. Para soportar el navegador Google Chrome, es necesario instalar un paquete que lo contenga, como por ejemplo Selenium.Chrome.WebDriver publicado por jbaranda, el cual incluye el ejecutable del driver en la carpeta bin respectiva del proyecto luego de compilarlo.

Una vez descargados e instalados los paquetes ya estamos listos para realizar nuestra primera prueba.

Primera prueba con Selenium

Para nuestra primera prueba, haremos uso de un formulario de inicio de sesión de un sitio de web de demostración llamado PHPTravels, en la URL http://www.phptravels.net/admin

Para ello, abrimos la clase creada al momento de crear el proyecto (por defecto es llamada UnitTest1), y agregamos las referencias para Selenium:

Luego, agregamos el siguiente método de ayuda para poder verificar si un elemento existe en la página web:

Finalmente sustituimos el método de prueba vacío, que fue creado por defecto, y creamos uno nuevo, llamado InicioSesion_ConCredencialesIncorrectas_MuestraAviso que consistirá en probar que si intentamos iniciar sesión ingresando credenciales incorrectas, se nos mostrará en pantalla una notificación indicando el error. El código final de la clase, con el nuevo método, es el siguiente:

Nota: El código fuente completo se encuentra disponible en GitHub: https://github.com/guillegr123/PruebaSelenium

Ejecutando la prueba unitaria

Para ejecutar la prueba unitaria, seleccionamos el nombre del método a probar, damos clic derecho, y seleccionamos la opción Ejecutar pruebas.


Esto abre el panel de Exploador de pruebas, y procede a ejecutar la prueba de forma automatizada, utilizando el navegador Google Chrome, elegido a través del driver utilizado. Se podrá observar como el navegador es abierto, y los pasos descritos en la prueba son ejecutados uno a uno, culminando con la verificación de que el elemento de notificación fue creado.


Una vez culminada la prueba, el resultado de esta es mostrado en el panel del Explorador de pruebas, con un ícono verde en caso de éxito, y uno rojo en caso de fallo.


viernes, 25 de agosto de 2017

Mi primera aplicación móvil


Hola a todos. Quería compartirles un vídeo que re-encontré hace poco, de mi primera aplicación móvil, que hice alrdedor del año 2013 (ya me sentí viejo). En esos tiempos tenía casi nulo conocimiento de Android, y del funcionamiento de aplicaciones móviles en general, por lo que decidí hacerla con Phonegap, ya que me permitía utilizar tecnologías que ya tenía algo de tiempo de conocer y siempre me han gustado.

La aplicación fue hecha para unos amigos que querían iniciar un negocio proporcionando un sistema en el que pequeños negocios se pudieran anunciar, publicar sus eventos, menús, etc., y que el público pudiera verlos a través de una aplicación móvil. El diseño y los íconos fueron proporcionados por ellos.

La aplicación en sí fue construida utilizando AppFramework de Intel (posiblemente la versión 1, no recuerdo), que era un framework para Javascript que utilizaba el patrón MVC, proveía una versión liviana de JQuery (jqLite), y Dot.js para la renderización de las vistas. Adicionalmente incluía componentes que emulaban los controles nativos de iOS.

La aplicación mostrada en el vídeo fue una de las versiones iniciales de la aplicación, en la que aún no había incluido el diseño elegido para la página de los negocios, y en la que el menú lateral era delgado. Este fue sustituido posteriormente por un menú más amplio, que incluía los títulos de las páginas en lugar de solo los íconos.

Fue una experiencia interesante que me permitió conocer y experimentar la creación de APIs web, y la forma en que estas interactuaban con las aplicaciones móviles. De hecho, mi primer servicio web y aplicación fue realizado para este proyecto.

Otros datos interesantes son:
  • La aplicación fue desarrollada principalmente en entorno Linux, con el fin de utilizar herramientas gratuitas pero poderosas, como el lenguaje de programación PHP, el IDE Netbeans, y el gestor de bases de datos MySQL; pero también debido a que la computadora no tenía los recursos suficientes para correr el emulador de Android en Windows, y este corría de forma más eficiente en Linux. Adicionalmente, la versión de Linux que utilizaba era Manjaro (mi primera experiencia con una distro basada en Arch Linux), con el entorno OpenBox, lo que la hacía significativamente más rápida y liviana que Windows y muchas versiones de Linux.
  • El vídeo fue grabado con una herramienta cuyo nombre no recuerdo, pero que irónicamente no poseía interfaz gráfica.
  • La ventana del emulador fue posicionada sobre la vista previa de una imagen de un teléfono celular, ajustada al tamaño del emulador, para que pareciera que el emulador tenía un skin de teléfono celular.
A continuación el vídeo:


jueves, 24 de agosto de 2017

Instalar SBT en Linux


Saludos. En esta entrada explicaré como instalar la Scala Build Tool en Linux. Los pasos los describo a continuación:
  1. Descargar la última versión de SBT desde la página de descargas oficial: http://www.scala-sbt.org/download.html
  2. Descomprimir el paquete descargado. Para efectos de este mini-tutorial, se descargó la versión 1.0.0 en paquete TGZ, y por cuestiones de orden, se descomprimirá en el folder /opt, por lo que en este caso los comandos a ejecutar son:

    $ su        # Iniciar sesión en modo súper usuario
    # mkdir sbt      # Crear directorio sbt, para colocar acá todas las versiones de SBT
    # cd sbt         # Navegar al directorio sbt
    # tar -xvzf /home/usuario/Downloads/sbt-1.0.0.tgz    # Descomprimir el paquete
  3. Hacer que el script sbt sea ejecutable:

    # chmod u+x sbt-1.0.0/bin/sbt
  4. Crear la variable de ambiente SBT_HOME, y agregar la ruta que contiene el script sbt a la variable de ambiente PATH. Para ello, se agrega al final del archivo ~/.bash_profile las siguientes líneas (para establecer las variables para terminales bash para el usuario actual):

    export SBT_HOME="/opt/sbt/sbt-1.0.0"
    export PATH="${PATH}:${SBT_HOME}/bin"
  5. Cerrar sesión e iniciar sesión nuevamente, para cargar las nuevas variables de entorno. Luego de ello, podemos abrir la terminal, y ejecutar el comando sbt, el cual ya estará disponible.

sábado, 19 de agosto de 2017

Desactualizando paquete de Arch Linux sin pacman


A.K.A. El fin de semana después del día que ingenuamente quise actualizar Arch Linux por partes en vez de actualizarlo todo.

Acerca de como comenzó todo

Pueden omitir esta sección. Todo comenzó un día que quise actualizar mi instalación de Apricity OS mientras estaba cenando, pero no quise actualizar todo debido a que necesitaba trabajar en la computadora después de cena, en Windows, y el tamaño de la actualización era de 1.2 Gb, por lo que con una magnífica conexión de 2Mbps, eso iba a tomar un largo rato.

Así que decidí a actualizar solo algunos paquetes que yo creía que eran independientes de todo lo demás. Empecé a ver la lista, y poco a poco fui actualizando algunos paquetes: geany, gimp, nano, samba... curl. Luego de eso seguí usando la computadora por un rato con normalidad, y la apagué. Todo bien.

Luego vine el fin de semana a querer utilizar la computadora para ver vídeos en Youtube mientras desayunaba. Para mis ratos de ocio prefiero ocupar Linux, ya que es más rápido, y no dependo de nada de Windows para ello. Todo bien. Luego noté que Variety no estaba corriendo (Variety se ha vuelto mi referencia de la salud del sistema operativo últimamente). ¡Qué raro?, pensé yo, pues lo había actualizado recientemente. Así que lo ejecuté desde la línea de comandos, para obtener más información. Apareció en pantalla un error de que no se podía encontrar la librería libssl.so.1.1.

Pensé que podría ser que Variety necesitaba otra actualización, así que procedí a actualizar la base de datos de paquetes de pacman, para ver si habían actualizaciones disponibles, con el comando:

sudo pacman -Syy

Cuando veo un error similar: No se puede encontrar la librería libssl.so.1.1. Así que ni modo, recurrí a Google para buscar alguna respuesta.

Después de un rato encontré un post que sugería crear enlaces simbólicos de las librerías requeridas hacia las librerías existentes, así que cree dos enlaces simbólicos, uno para libssl.so.1.1 y otro para libcrypto.so.1.1:

ln -s /usr/lib/libssl.so.1.0.0 /usr/lib/libssl.so.1.1
ln -s /usr/lib/libcrypto.so.1.0.0 /usr/lib/libcrypto.so.1.1

Luego intenté nuevamente actualizar la lista de paquetes de pacman, y obtuve el siguiente error:


Y allí me acordé: había actualizado curl, pero lo que no sabía es que curl requería versiones actualizadas de libssl y libcrypto. Además, lo había actualizado por sí solo pensando que yo había sido el que había instalado el paquete y que no había dependencias de este.  Pero para mi horror, el mismísimo pacman dependía de curl.

Intenté buscar una forma de desactualizar curl, pero la forma estándar requería usar pacman, lo cual fue imposible. Oh, el horror.


Así que ni modo, a buscar una alternativa para hacer la actualización a pata. Gracias a Dios me encontré con esta entrada en Reddit: Pacman libcritpto.so.1.1 errors.

Desactualizando paquete de Arch sin pacman

Sabiendo que en mi caso el error había sido solamente con curl, procedí a realizar la desinstalación de la versión más nueva que encontré en /var/cache/pacman/pkg, la cual era curl-7.55.1-1. Ejecuté el siguiente comando, como super usuario:

tar -tf /var/cache/pacman/pkg/curl-7.55.1-1-x86_64.pkg.tar.xz | sed s:^:/: | grep -v /$ | xargs rm

Explicando el comando por partes:
PasoComandoDescripción
1 tar -tf /var/cache/pacman/pkg/curl-7.55.1-1-x86_64.pkg.tar.xz
Obtiene la lista de archivos contenidos en el paquete.
2 sed s:^:/:
Agrega / al principio de la ruta de cada archivo.
3 grep -v /$
Del listado anterior, quita los elementos que terminen en /, ya que estos corresponden a carpetas.
4 xargs rm
Elimina los archivos listados.

Luego, procedí a instalar la versión previa disponible en el cache de paquetes, que era curl-7.52.1-2, con el siguiente comando (siempre como usuario root):

tar -xf /var/cache/pacman/pkg/curl-7.52.1-2-x86_64.pkg.tar.xz

Y finalmente probé actualizar nuevamente la base de datos de pacman, y todo resultó bien:


Lección aprendida: No actualizar Arch Linux a medias.

sábado, 12 de agosto de 2017

Obtener documentación de base de datos SQL Server

Por cuestiones de tiempo, esta entrada es solo un "dump" de código fuente. Asumiendo que hiciste tu tarea de colocar los comentarios de los objetos de la base de datos utilizando la propiedad extendida MS_Description, a continuación incluyo unas consultas para obtener la documentación respectiva de los objetos más relevantes de la base de datos.

Esquemas

SELECT
  s.name AS esquema,
  ep.value AS descripcion
FROM sys.schemas s
  left join sys.extended_properties ep
    ON s.schema_id = ep.major_id
      AND ep.name = 'MS_Description'
WHERE s.name NOT IN (
  -- Lista de esquemas a ignorar
  'db_accessadmin',
  'db_backupoperator',
  'db_datareader',
  'db_datawriter',
  'db_ddladmin',
  'db_denydatareader',
  'db_denydatawriter',
  'db_owner',
  'db_securityadmin',
  'guest',
  'INFORMATION_SCHEMA',
  'sys'
)
ORDER BY 1

Tablas

SELECT
  SCHEMA_NAME(schema_id) esquema,
  t.name AS tabla,
  ep.value AS descripcion
FROM sys.tables AS t
  left join sys.extended_properties ep
    ON t.object_id = ep.major_id
      AND 0 = ep.minor_id
      AND ep.name = 'MS_Description'
ORDER BY 1, t.name

Columnas

Nota: No he descubierto aún por qué, pero hay ciertos casos en los que la columna que es llave primaria me aparece duplicada. Cualquier ayuda es bienvenida :)

SELECT
  SCHEMA_NAME(schema_id) + '.' + t.name AS tabla,
  c.name AS columna,
  TYPE_NAME(c.system_type_id) AS tipo_de_datos,
  CASE c.max_length
    WHEN -1 THEN 'MAX'
    ELSE CAST(c.max_length AS VARCHAR(100))
  END tamano,
  CASE c.is_nullable
    WHEN 1 THEN 'Sí'
    ELSE 'No'
  END AS permite_nulos,
  CASE i.is_primary_key
    WHEN 1 THEN 'Sí'
    ELSE 'No'
  END AS llave_primaria,
  CASE
    WHEN fk.referenced_column_id IS NOT NULL THEN 'Sí'
    ELSE 'No'
  END AS llave_foranea,
  ep.value AS descripcion
FROM sys.tables AS t
  INNER JOIN sys.columns c
    ON t.object_id = c.object_id
  LEFT JOIN sys.index_columns AS ic
    ON ic.OBJECT_ID = c.OBJECT_ID AND ic.column_id = c.column_id
  LEFT JOIN sys.indexes AS i
    ON i.OBJECT_ID = ic.OBJECT_ID AND i.index_id = ic.index_id
  LEFT JOIN sys.foreign_key_columns AS fk
    ON fk.parent_object_id = c.object_id
      AND fk.parent_column_id = c.column_id
  LEFT JOIN sys.extended_properties ep
    ON t.object_id = ep.major_id
      AND c.column_id = ep.minor_id
      AND ep.name = 'MS_Description'
ORDER BY 1, c.column_id

Llaves foráneas

Nota: Esta consulta devuelve una fila por columna, por lo que aparecerán tantas filas como columnas incluya la llave.

SELECT
  SCHEMA_NAME(t.schema_id) + '.' + t.name as tabla_hija,
  c.name as tabla_hija_columna,
  SCHEMA_NAME(tr.schema_id) + '.' + tr.name tabla_padre,
  cr.name tabla_padre_columna,
  fk.name fk_nombre,
  CASE fk.update_referential_action
    WHEN 0 THEN 'NO ACTION'
    WHEN 1 THEN 'CASCADE'
    WHEN 2 THEN 'SET NULL'
    WHEN 3 THEN 'SET DEFAULT'
  END regla_actualizacion,
  CASE fk.delete_referential_action
    WHEN 0 THEN 'NO ACTION'
    WHEN 1 THEN 'CASCADE'
    WHEN 2 THEN 'SET NULL'
    WHEN 3 THEN 'SET DEFAULT'
  END regla_eliminacion
FROM sys.foreign_key_columns as fkc
  INNER JOIN sys.foreign_keys fk
    ON fkc.constraint_object_id = fk.object_id
  INNER JOIN sys.tables as t
    ON fkc.parent_object_id = t.object_id
  INNER JOIN sys.columns as c
    ON fkc.parent_object_id = c.object_id
      and fkc.parent_column_id = c.column_id
  INNER JOIN sys.tables as tr
    ON fkc.referenced_object_id = tr.object_id
  INNER JOIN sys.columns as cr
    ON fkc.referenced_object_id = cr.object_id
      and fkc.referenced_column_id = cr.column_id
ORDER BY 1, fkc.constraint_column_id

Índices

Nota: Esta consulta devuelve una fila por índice, y muestra las columnas separadas por comas.

SELECT DISTINCT
  da.tabla AS tabla,
  i.name AS indice,
  da.tipo AS tipo,
  CASE i.is_primary_key
    WHEN 1 THEN 'Sí'
    ELSE 'No'
  END AS llave_primaria,
  CASE i.is_unique
    WHEN 1 THEN 'Sí'
    ELSE 'No'
  END AS llave_unica,
  CASE i.is_unique_constraint
    WHEN 1 THEN 'Sí'
    ELSE 'No'
  END AS restriccion_unicidad,
  LEFT(cols.names, LEN(cols.names) - 1) columnas
FROM sys.tables AS t
  INNER JOIN sys.columns c
    ON t.object_id = c.object_id
  INNER JOIN sys.index_columns AS ic
    ON ic.OBJECT_ID = c.OBJECT_ID AND ic.column_id = c.column_id
  INNER JOIN sys.indexes AS i
    ON i.OBJECT_ID = ic.OBJECT_ID AND i.index_id = ic.index_id
  CROSS APPLY (
    SELECT
      SCHEMA_NAME(schema_id) + '.' + t.name tabla,
      CASE i.index_id
        WHEN 1 THEN 'CLUSTERED'
        ELSE 'NONCLUSTERED'
      END AS tipo
  ) da
  CROSS APPLY (
    SELECT c_i.name + ','
    FROM sys.columns c_i
      INNER JOIN sys.index_columns AS ic_i
        ON ic_i.OBJECT_ID = c_i.OBJECT_ID AND ic_i.column_id = c_i.column_id
    WHERE i.OBJECT_ID = ic_i.OBJECT_ID AND i.index_id = ic_i.index_id
    FOR XML PATH ('')
  ) cols(names)
ORDER BY 1, 2, 3

Sobreviviendo a un OS descontinuado - Apricity OS


Saludos a todos, ya tenía un largo tiempo de no escribir en el blog, debido a algunos proyectos que han consumido demasiada parte de mi tiempo libre :(

Precisamente debido a esto, ya que los proyectos habían sido desarrollados en en Windows (Visual Studio, .NET, y todas esas cosas del imperio), ya tenía un  largo rato de no utilizar el sistema Linux que también tengo instalado en mi computadora personal. Pues bien, esta mañana finalmente encendí mi computadora e ingresé a mi muy apreciada instalación de Apricity OS, y como primera tarea decidí que quería hacer funcionar el administrador de fondos de escritorio que tengo instalado, llamado Variety, ya que la ultima vez que entré al sistema habia notado que este había dejado de funcionar y que no podría ser iniciado. Intente ejecutarlo desde la línea de comandos, para obtener más información acerca del posible error, y vi un mensaje que me indicaba que la razón por la cual no estaba funcionando era que la versión de Variety que tenía instalada era antigua, y que debía actualizar a la versión más reciente. Yo le temo a las actualizaciones, pues tienden a romper cosas, en Windows y Linux, pero bueno, era solo un paquete, así que procedí a la actualización usando la confiable herramienta pacman.

sudo pacman -S variety

Pero tristemente no se pudo, ya que en su lugar me apareció el siguiente mensaje:


Siendo un noob en Linux, y en particular en Arch, me puse a investigar en google, y de lo que logré encontrar, decidí que tal vez necesitaba actualizar las bases de datos de los repositorios, así que intenté eso:

sudo pacman -Syy

Y luego me apareció un mensaje más claro:


Falló la descarga del archivo 'apricity-core.db' desde static.aprictyoscom : Falló la conexión a static.apricityoscom puerto 80: Conexión rechazada

La triste sorpresa

Mmm, ¿será tal vez que el servidor no está disponible?
¿Habrá algún espejo para poder usar?
¿Será que iban a hacer mantenimiento de sus servidores este día?
 Bueno, a googlear para buscar alguna noticia. Y allí fue cuando, para mi sorpresa, me dí cuenta de la triste noticia: Apricity OS ha sido descontinuado, desde el 6 de mayo del presente 2017. Ingresando a su página de Github, se puede ver el siguiente mensaje:


¿Apricity OS?

La noticia es triste para mí, ya que Apricity OS había sido mi versión favorita de Linux, desde que empecé a ocupar Linux. Apricity OS era una distro basada en Arch Linux, que intentaba ofrecer lo mejor de este sistema operativo de un forma amigable y sencilla. Entre las cosas buenas que tenía era que oseía un instalador gráfico para facilitar la instalación y actualización de paquetes. También compartía el modelo de actualización de liberación continua de Arch, lo que permitía actualizar el sistema sin tener que instalarlo desde cero nuevamente cada vez que hubiera una nueva versión. Otra característica interesante es que incluía ICE, que es una aplicación que permite utilizar auna aplicación web como si fuera una aplicación de escritorio normal. También poseía una interfaz con un diseño limpio y moderno utilizando Gnome 3.



¿Y ahora qué?

La verdad es que a mí me encanta este sistema operativo, sigue siendo el que más me ha gustado, y considero que siendo basado en Arch, aún puedo continuar utilizándolo, ya que buena parte de los paquetes provienen de ese entorno. Bajo esta premisa, mi siguiente paso fue desactivar el repositorio de Apricity OS de la configuración de pacman. Para ello abrí el archivo /etc/pacman.conf en un editor de texto con el usuario administrador (en mi caso utilicé el comando gksudo geany /etc/pacman.conf para ello). Luego marqué como comentarios las siguientes líneas:

[apricity-core]
SigLevel = Required
Server = http://static.apricityos.com/apricity-core-signed/

Así:

#[apricity-core]
#SigLevel = Required
#Server = http://static.apricityos.com/apricity-core-signed/

Con ello pacman ignora el repositorio de Apricity OS, lo cual evita que se produzca el fallo debido a que no puede descargar su base de datos. Hecho esto ya pude actualizar el paquete que necesitaba.

Conclusiones finales

Es una triste noticia que un sistema operativo tan eficiente, elegante y amigable haya llegado a su fin, en un tiempo tan corto (creo que fue un poco más de un año el tiempo que el proyecto estuvo disponible), pero así es el mundo del software libre, ya que se depende del trabajo voluntario de comunidades de desarrolladores que buscan ofrecer piezas de software increíbles sin esperar nada a cambio. "Por amor al arte", como dicen. Solo nos queda agradecer a estas personas por la maravillosa experiencia que nos ofrecieron al traer al mundo a Apricity OS, y también nos deja la motivación para que nosotros nos animemos a integrarnos a alguna de estas apreciables comunidades.

Saludos, y hasta la próxima.
Con la tecnología de Blogger.