ENUM en JAVA

ENUMS EN JAVA

1.- Enum En Java

¿Qué es un ENUM? En su forma más simple, una enumeración es una lista de constantes con nombre que definen un nuevo tipo de datos. Un objeto de un tipo de enumeración sólo puede contener los valores definidos por la lista. Por lo tanto, una enumeración le brinda una manera de definir con precisión un nuevo tipo de datos que tiene un número fijo de valores válidos.

Por ejemplo, los 4 palos en un mazo de cartas pueden ser 4 enumeradores llamados Flores, Diamantes, Corazones y Espadas, que pertenecen a un tipo enumerado llamado Cartas. Otros ejemplos incluyen tipos de enumerados naturales (como los planetas, días de la semana, meses del año, colores, direcciones, etc.).

Desde una perspectiva de programación, las enumeraciones son útiles siempre que necesite definir un conjunto de valores que represente una colección de elementos. Por ejemplo, puede usar una enumeración para representar un conjunto de códigos de estado, como éxito, espera, error y reintentos, que indican el progreso de alguna acción. En el pasado, dichos valores se definían como variables finales, pero las enumeraciones ofrecen un enfoque más estructurado.

2.- Cómo funcionan los Enum

¿Qué es un ENUM en Java? Los enum en Java se usan cuando conocemos todos los valores posibles en tiempo de compilación, como las opciones de un menú, los modos de redondeo, los indicadores de línea de comando, etc. No es necesario que el conjunto de constantes en un tipo de enumeración permanezca fijo para siempre.

En Java (desde 1.5), las enumeraciones se representan utilizando el tipo de datos enum. Las enumeraciones Java son más poderosas que las enumeraciones C/C++. En Java, también podemos agregarle variables, métodos y constructores. El objetivo principal de enum es definir nuestros propios tipos de datos (tipos de datos enumerados).

3.- Declaración de enum en Java

La declaración de un Enum puede hacerse fuera de una clase, o dentro de una clase (class), pero NO dentro de un método.

Por ejemplo;

// Un simple ejemplo donde se declara enum

// fuera de cualquier clase (Nota la palabra enum en lugar de la palabra class)

enum Color {

ROJO, VERDE, AZUL;

}

public class Test {

// El método

public static void main(String[] args) {

Color c1 = Color.ROJO;

System.out.println(c1);

}

}

Salida:

ROJO

1.- Una enumeración se crea usando la palabra clave enum

2.- La primera línea dentro de enum debe ser una lista de constantes, y luego otras cosas cómo métodos, variables y constructores.

3.- De acuerdo con las convenciones de nomenclatura de Java, se recomienda que nombremos las constantes con mayúsculas.

4.- Ejemplo con enum en Java

Por ejemplo, aquí hay una enumeración simple que enumera varias formas de trasporte:

// Una enumeración de transporte

enum Transporte {

COCHE, CAMION, AVION, TREN, BARCO;

}

Los identificadores COCHE, CAMION, etc., se denominan constantes de enumeración. Cada uno se declara implicitamente como un miembro público (public) y estático (static) de Transporte. Además, el tipo de constantes de enumeración es el tipo de enumeración en el que se declaran las constantes, que es Transporte en este caso. Por lo tanto, en el lenguaje Java, estas constantes se llaman auto-tipado.

Una vez que haya definido una enumeración, puede crear una variable de ese tipo. Sin embargo, aunque las enumeraciones definene un tipo de clase, no crea una instancia de una enumeración usando new. En cambio, declaras y utilizas una variable de enumeración de la misma manera que haces uno de los tipos primitivos. Por ejemplo, esto declara tp como una variable del tipo de enumeración Transporte:

Transporte tp;

Como tp es de tipo Transporte, los únicos valores que se le pueden asignar son los definidos por la enumeración. Por ejemplo, esto asigna tp el valor AVION:

tp = Transporte.AVION;

Se pueden comparar dos constantes de enumeración utilizando el operador relacional ==. Por ejemplo, esta declaración compara el valor en tp con la constante TREN:

if (tp == Transporte.TREN) // ...

Un valor de enumeración también se puede usar para controlar una sentencia switch. Por supuesto, todas las declaraciones de case deben usar constantes de la misma enumeración que la utilizada por la expresión de switch. Por ejemplo, este switch es perfectamente válido:

// Uso de enum para controlar una sentencia switch

switch(tp) {

case COCHE:

//

case CAMION:

//

}

Observe que en las sentencias case, los nombres de las constantes de enumeración se usan sin estar calificados por el nombre del tipo de la enumeración. Es decir, se utiliza CAMION no Transporte.CAMION. Esto se debe a que el tipo de la enumeración en la expresión de switch ya ha especificado implícitamente el tipo de la enumeración de las constantes case.

No es necesario calificar las constantes en las declaraciones de case con su nombre de tipo enum. De hecho, intentar hacerlo provocará un error de compilación.

4.1.- Código de Ejemplo

Cuando se muestra una constante de enumeración, como en una instrucción println(), se genera su nombre. Por ejemplo, dada esta declaración:

System.out.println(Transporte.BARCO);

se muestra el nombre BARCO.

El siguiente programa reúne todas las piezas y muestra la enumeración Transporte:

// Una enumeración de transporte

enum Transporte {

COCHE, CAMION, AVION, TREN, BARCO;

}

class Enumerados {

public static void main(String[] args) {

Transporte tp;

tp = Transporte.AVION;

System.out.println("Valor de tp: " + tp);

System.out.println();

tp = Transporte.TREN;

// Comparación de 2 valores enum

if (tp == Transporte.TREN)

Sytem.out.println("tp tiene el valor de TREN\n");

// enum para controlar sentencia switch

switch(tp) {

case COCHE:

System.out.println("Un auto lleva personas");

break;

case CAMION:

System.out.println("Un camión lleva carga");

break;

case AVION:

System.out.println("Un avión vuela");

break;

case TREN:

System.out.println("Un tren corre sobre railes");

break;

case BARCO:

System.out.println("Un barco navega en el agua");

break;

}

}

}

Salida:


Valor de tp: AVION

tp tiene el valor de TREN

Un tren corre sobre railes

Antes de continuar, es necesario hacer un punto sobre estilo. Las constantes en Trasporte usan mayúsculas. (Por lo tanto, se usa COCHE, no coche). Sin embargo, no se requiere el uso de mayúsculas. En otras palabras, no existe una regla que requiera que las constantes de enumeración estén en mayúsculas.

Debido a que las enumeraciones a menudo reemplazan las variables finales, que tradicionalmente se han usado en mayúsculas, algunos programadores creen qeu las constantes de una enumeración en mayúsculas también son apropiadas. Por supuesto, hay otros puntos de vista y estilos.

5.- Puntos importantes de enum

1.- Cada enm es implementado internamente mediante el uso de class.

// internamente enum Color se convierte en

class Color {

public static final Color ROJO = new Color();

public static final Color AZUL = new Color();

public static final Color VERDE = new Color();

}

2.- Cada constante enum representa un objeto de tipo enum.

3.- El tipo enum se puede pasar como argumento para el switch

// Un programa Java para demostrar el trabajo de enum

// en case de switch (Archivo Test.java)

import java.util.Scanner;

// Una clase enum

enum Day {

LUNES, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO;

}

// Controlador de clase que contiene un objeto de "día" y

// main().

public class Test {

Dia dia;

// Constructor

public Test(Dia dia) {

this.dia = dia;

}

// Imprime una línea sobre el DIA usando switch

public void DiaEs() {

switch (dia) {

case LUNES:

System.out.println("Los lunes son feos");

break;

case VIERNES:

System.out.println("Los viernes son mejores");

break;

case SABADO:

case DOMINGO:

System.out.println("Los fines de semana son mejores");

break;

default:

System.out.println("Los días entre semana son regulares");

break;

}

}

// Método

public static void main(String[] args) {

String str = "LUNES";

Test t1 = new Test(Dia.valueOf(str));

t1.dayIsLike();

}

}

Salida:

Los lunes son feos

1.- Cada constante enum siempre es implícitamente public static final. Entonces, como es static, podemos acceder utilizando el nombre del enum. Y, como es final, no podemos crear enumeraciones "hijas".

2.- Podemos declarar el método main() dentro de enum. Por lo tanto, podemos invocar enum directamente desde el Símbolo del sistema.

Por ejemplo:

// Un programa Java para demostrar que podemos tener

// main() dentro enum

enum Color {

ROJO, VERDE, AZUL;

// Método

public static void main(String[] args) {

Color c1 = Color.ROJO;

System.out.println(c1);

}

}

Salida:

ROJO

Aunque los ejemplos anteriores muetran la mecánica de crear y usar una enumeración, no muestran todas sus capacidades. A diferencia de la forma en que se implementan las enumeraciones en algunos otros lenguajes, Java implementa enumeraciones como tipos de clases. Aunque no crea una instancia de una enumeración usando new, actúa de forma muy similar a otras clases.

El hecho de que enum define una clase permite que la enumeración de Java tenga poderes que las enumeraciones en otros lenguajes no tienen. Por ejemplo, puede darle constructores, agregar variables y métodos de instancia, e incluso implementar interfaces.

6.- Métodos values(), ordinal() y valueOf()

Todas las enumeraciones tienen automáticamente dos metodos predefinidos: values() y valueOf(). Sus formas generales se muestran aquí:

public static tipo-enum[ ] values()

public static tipo-enum valueOf(String str)

1.- Estos métodos están presentes dentro de java.lang.Enum

2.- El método values() se puede usar para devolver todos los valores presentes de enum.

3.- El orden es importante en las enumeraciones. Al usar el método ordinal(), se puede encontrar cada índice de la constante enum, al igual que el índice de matriz.

4.- El método valueOf() devuelve la constante enum del valor de cadena específicado, si existe.

Por ejemplo:

// Programa Java para demostrar el funcionamiento de values(),

// ordinal() y valueOf()

enum Color {

ROJO, VERDE, AZUL;

}

public class Test {

public static void main(String[] args) {

// Llamando a values()

Color arr[] = Color.values();

// enum con bucle

for (Color col : arr) {

// Llamando a ordinal() para encontrar el índice de color

System.out.println(col + " en el índice " + col.ordinal());

}

// Usando valueOf(). Devuelve un objeto de Color con la constante dada

// La segunda línea comentada causa la excepción IllegalArgumentException

System.out.println(Color.valueOf("ROJO");

// System.out.println(Color.valueOf("BLANCO"));

}

}


Salida:

ROJO en el índice 0

VERDE en el índice 1

AZUL en el índice 2

ROJO

7.- enum: Constructores, métodos, variables de instancia

Es importante comprender que cada constante de enumeración es un objeto de su tipo de enumeración. Por lo tanto, una enumeración puede definir constructores, agregar metodos y tener variables de instancia.

Cuando define un constructor para una enumeración, se llama al constructor cuando se crea cada constante de enumeración. Cada constante de enumeración puede llamar a cualquier método definido por la enumeración. Cada constante de enumeración tiene su propia copia de cualquier variable de instancia definida por la enumeración.

1.- enum puede contener un constructor y se ejecuta por separado para cada constante enum en el momento de la carga de la clase enum.

2.- No podemos crear objetos enum explícitamente y, por lo tanto, no podemos invocar el constructor de enum directamente.

La siguiente versión de Transporte ilustra el uso de un constructor, una variable de instancia y un método. Da a cada tipo de transporte una velocidad típica:

// Uso de un constructor, una variable de instancia y un método

enum Transporte {

COCHE(60), CAMION(50), AVION(600), TREN(70), BARCO(20);

private int velocidad; // velocidad típica de cada transporte

// Añadir un constructor

Transporte(int s) {

velocidad = s;

}

// Añadir un método

int getVelocidad() {

return velocidad;

}

}


class Enumerados {

public static void main(String[] args) {

Transporte tp;

// Mostrar la velocidad de un avión

System.out.println("La velocidad típica para un avión es: " +

Transporte.AVION.getVelocidad() + " millas por hora.\n");

// Mostrar todas las velocidades y transportes

System.out.println("Todas las velocidades de transporte: ");

for (Transporte t : Transporte.values())

System.out.println(t + ": velocidad típica es " + t.getVelocidad() +

" millas por hora.");

}

}


La velocidad típica para un avión es: 600 millas por hora.

Todas las velocidades del transporte:

COCHE: velocidad típica es 60 millas por hora.

CAMION: velocidad típica es 50 millas por hora.

AVION: velocidad típica es 600 millas por hora.

TREN: velocidad típica es 70 millas por hora.

BARCO: velocidad típica es 20 millas por hora.


7.1.- Explicación del Ejemplo

Esta versión de Transporte agrega tres cosas. La primera es la variable de instancia velocidad, que se usa para mantener la velocidad de cada tipo de transporte. El segundo es el constructor Transporte, que pasa la velocidad de un transporte. El tercero es el método getVelocidad(), que devuelve el valor de velocidad.

Cuando la variable tp se declara en el main(), el constructor de Transporte se llama una vez para cada constante qeu se específica. Observe cómo se especifican los argumentos para el constructor, poniéndolos entre paréntesis, después de cada constante, como se muestra aquí:

COCHE(60), CAMIN(50), AVION(600), TREN(70), BARCO(20);

Estos valores se pasan al parámetro de Transporte(), que luego asigna este valor a la velocidad. Hay algo más que notar sobre la lista de constantes de enumeración: termina con un punto y coma. Es decir, la última constante, BARCO, va seguida de un punto y coma. Cuando una enumeración contiene otros miembros, la lista de enumeración debe terminar en punto y coma.

Como cada constante de enumeración tiene su propia copia de velocidad, puede obtener la velocidad de un tipo de transporte específicado llamando a getVelocidad(). Por ejemplo, en main() la velocidad de un avión se obtiene mediante la siguiente llamada:

Transporte.AVION.getVelocidad()

La velocidad de cada transporte se obtiene al recorrer la enumeración mediante un bucle for. Como hay una copia de velocidad para cada constante de enumeración, el valor asociado con una constante es separado y distinto del valor asociado con otra constante. Este es un concepto poderoso, que está disponible solo cuando las enumeraciones se implementan como clases, como lo hace Java.

Aunque el ejemplo anterior contiene solo un constructor, una enumeración puede ofrecer dos o más formas de sobrecargas, al igual que cualquier otra clase.

8.- Enum y Herencia

Hay dos restricciones que se aplican a las enumeraciones. Primero, una enumeración no puede heredar otra clase. En segundo lugar, una enumeración no puede ser una superclase.

Esto significa que una enumeración no se puede extender. De lo contrario, enum actúa como cualquier otro tipo de clase. La clave es recordar que cada una de las constantes de enumeración es un objeto de la clase en la que está definida.

1.- Aunque no puede heredar una super clase al declarar una enumeración, todas las enumeraciones heredan automáticamente una java.lang.Enum. Esta clase define varios métodos que están disponibles para el uso de todas las enumeraciones.

2.- Muy a menudo, no necesitará usar estos métodos, pero hay dos que puede emplear ocasionalmente: ordinal() y compareTo().

3.- El método toString() se reemplaza en la clase java.lang.Enum, que devuelve el nombre de la constante enum.

4.- enum puede implementar muchas interfaces.

8.1.- Uso de ordinal() y compareTo()

El método ordinal() se muestra aquí:

final int ordinal()

Devuelve el valor ordinal de la constante invocadora. Los valores ordinales comienzan en cero. Por lo tanto, en la enumeración Transporte, COCHE tiene un valor ordinal de cero, CAMION tiene un valor ordinal de 1, AVION tiene un valor ordinal de 2, y así sucesivamente.

Puede comparar el valor ordinal de dos constantes de la misma enumeración utilizando el método compareTo(). Tiene esta forma general:

final int compareTo(tipo-enum e)

Aquí, tipo-enum es el tipo de enumeración y e es la constante que se compara con la constante de invocación. Recuerde, tanto la constante de invocación como e deben ser de la misma enumeración. Si la constante de invocación tiene un valor ordinal menor que e, entonces compareTo() devuelve un valor negativo. Si los dos valores ordinales son iguales, se devuelve cero. Si la constante de invocación tiene un valor ordinal mayor que e, se devuelve un valor positivo.

// Demostración de ordinal() y compareTo()

enum Transporte {

COCHE, CAMION, AVION, TREN, BARCO;

}

class Enumerados {

public static void main(String[] args) {

Transporte tp, tp2, tp3;

// Obtenga todos los valores ordinales usanod ordinal()

System.out.println("Aquí están todas las constantes de Transporte " +

"y sus valores ordinales: ");

for (Transporte t : Transporte.values())

System.out.println(t + " " + t.ordinal());

tp = Transporte.AVION;

tp2 = Transporte.TREN;

tp3 = Transporte.AVION;

System.out.println();

// Uso de compareTo()

if (tp.compareTo(tp2) < 0)

System.out.println(tp + " llega antes que " + tp2);

if (tp.compareTo(tp2) > 0)

System.out.println(tp2 + " llega antes que " + tp);

if (tp.compareTo(tp3) == 0)

System.out.println(tp + es igual que " + tp3);

}

}


Salida:

Aquí están todas las constantes de Transporte y sus valores ordinales:

COCHE 0

CAMION 1

AVION 2

TREN 3

BARCO 4

AVION llega antes que TREN

AVION es igual que AVION

9.- enum y Métodos

1.- enum puede contener métodos concretos, es decir, no tiene ningún método abstracto (abstract).

Por ejemplo:

// Programa Java para demostrar que los enum pueden tener constructores

// y métodos concretos.

// Una enumeración (Note la palabra enum en lugar de class)

enum Color {

ROJO, VERDE, AZUL;

// enum constructor llamado por separado para cada constante

private Color() {

System.out.println("Constructor llamado para: " + this.toString());

}

// Sólo métodos concretos (no abstractos) permitidos

public void colofInfo() {

System.out.println("Color Universal");

}

public class Test {

// Método

public static void main(String[] args) {

Color c1 = Color.ROJO;

System.out.println(c1);

c1.colorInfo();

}

}

Salida:

Constructor llamado para: RED

Constructor llamado para: VERDE

Constructor llamado para: AZUL

ROJO

Color universal


 

Hola Mundo en Spring Boot en Consola

 

APLICACIÓN DE CONSOLA CON SPRING BOOT

Todo programador Java ha implementado el típico "hola mundo".

Para ello, es necesario crear una clase, que implemente el método main y en su interior el código que queramos ejecutar. Este método es el punto de entrada de la Maquina Virtual de Java hacía nuestro código.

1.- Creando e importando el proyecto

En primer lugar debemos crear un proyecto. Para ello entramos en la página de Spring Initializr y generamos nuestro proyecto.

A continuación, descomprimimos el zip descargado e importamos en nuestro IDE el proyecto que contiene. Hemos especificado que sea un proyecto Maven, con Java 8 como lenguaje de programación, con versión 2.2.6 de Spring Boot y que genere un Jar en el empaquetado, aunque se puede modificar en función de las necesidades.

2.- Creando nuestro "main"

En este paso se crea la clase, la cual será el punto de entrada a nuestro código. Para ello, creamos una clase Main la cual implementará la interfaz CommandLineRunner.

La interfaz define un método llamado run y es el equivalente al método main. Finalmente le añadimos el decorador @Component para que Spring Boot lo reconozca y ya tenemos lista nuestra aplicación.

3.- Hello World

Finalmente dentro del método run escribimos lo que pondríamos en el método main, en nuestro caso vamos a hacer que imprima por consola "Hola Mundo":

@Component

public class Main implements CommandLineRunner {

@Override

public void run(String... args) throws Exception {

System.out.println("Hola Mundo");

}

}

4.- Conclusiones

Con esta implementación, podemos tener la simplicidad de un proyecto Java que se compila como un jar y ejecuta dentro alguna lógica simple, junto con todo el potencial de Spring Boot.

Es posible incluir otras dependencias como Spring Data o Spring Email para incluir mayor funcionalidad a nuestro servicio Java.




RELACIONES EN TABLAS EN JPA

La entidad o entidad extendida será la clase con la que realmente trabajemos, ya que tiene las columnas de la clase que hereda y la funcionalidad que añadamos según nuestras necesidades. Al igual que con las super clases, se recomienda crear un paquete dentro del proyecto donde guardar todas nuestras entidades.

La principal diferencia es que esta clase si estará marcada con la anotación @Entity y tendrá que extender de la super clase e implementar Serializable:

@Entity

@Table(name = "TABLA_EJEMPLO")
public class TablaEjemploExtends extends TablaEjemplo implements Serializable {...}

Figura 14. Entidad extendida de ejemplo

El punto más importante que vamos a desarrollar de la lógica que se puede añadir en las clases extendidas son las relaciones Hibernate entre entidades:

@OneToOne

@OneToOne(cascade = CascadeType.ALL, mappedBy = "nombreAtributo",
fetch = FetchType.LAZY)

Figura 15. Relación @OneToOne

La anotación @OneToOne tiene los siguientes atributos:

1.- Cascade: es tarea del programador acertar en el uso de este atributo ya que no hay una regla universal. En este caso se ha usado CascadeType.ALL para darle legibilidad del código y para que se actualice la tabla destino ante cualquier operación. No se recomiendo usar como comodín.

2.- MappedBy: entre comillas se debe insertar el nombre del atributo que deseemos relacionar en la tabla destino.

3.- Fetch: no carga la relación a menos que se invoque el getter. Para realizar lo contrario, marcar como EAGER.

@OneToMay

A diferencia de la anterior, si se marca una relación como @OneToMany debe existir otra que sea @ManyToOne

@OneToMany(cascade = CascadeType.ALL, mappedBy = "test",

FetchType.LAZY)
protected List<CfgTestOpcionExtends> cfgTestOpcionExtendsList;

Figura 16. Relación @OneToMany

Identica a la anterior salvo porque declara una lista como atributo. Es olbigatorio el mappedBy.

@JoinColumn(name = "ID_TEST" referencedColumnName = "ID",

nullable = false, insertable = false, updatable = false)
@ManyToOne(opcional = false, fetch = FetchTye.LAZY)
protected CfgTestExtends test;

Figura 17. Relación @ManyToOne para satisfacer @OneToMany

A destacar, la anotación @JoinColumn. Puede confundirse con @Column, pero esta anotación nos permite definir el nombre exacto de la columna, si debe insertable, actualizable y nulo. En este caso, el atributo name hace referencia al nombre que deseemos que tenga la columna de esa clase, pero el atributo referencedColumnName es el nombre que le hemos puesto en la clase destino.

@ManyToOne

Realmente ya estaría explicada con lo mencionada anteriormente, pero se va a profundizar en el caso de que la relación una dos columnas:

@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)

@JoinColumns({@JoinColumn(name = "COLUMNA_UNO",

@JoinColumn(name = "COLUMNA_DOS")})
private ClaseRelacionada nombreClaseRelacionada;

Figura 18. Múltiples columnas en una unión

Gracias a la anotación @JoinColumns podremos crear múltiples columnas de la unión.

@ManyToMany

Para entender este caso, vamos a plantear la situación en la que un usuario puede tener diversos roles y los roles pueden estar asignados a más de un usuario. La forma en la que podemos relacionar ambas entidades es la siguiente:

En la clase Usuarios:

@JoinTable(name = "ROL_USUARIOS", joinColumns = {

@JoinColumn(name = "USUARIO", referencedColumnName = "USUARIO",
nullable = false) },
inverseJoinColumns = {
@JoinColumn(name = "ID_ROL", referencedColumnName = "ID",
nullable = false})
@ManyToMany(fetch = FetchType.LAZY)
private List<RolesExtends> rolesList;

Figura 19. Relación @ManyToMany en usuarios

La forma en la que hemos orientado la solución es la de crear una tercera tabla adicional que reúna una columna de cada tabla. La anotación @JoinTable realiza dicha acción en la nueva tabla ROL_USUARIOS uniendo el identificador del usuario y el identificador del rol. Se usa inverseJoinColumns para establecer la columna que no pertenece a la clase donde se implementa.

En este caso, se llama a la ajena Roles desde la clase Usuarios.

En la clase Roles:

@ManyToMany(mappedBy = "rolesList", fetch = FetchType.LAZY)
private List<UsuariosExtends> usuariosList;

Dado que se ha realizado el proceso principal en la clase Usuarios, en ésta solo necesitamos indicar en el mappedBy el nombre del atributo al cual hace referencia. 

TDD 1

Documentación de pruebas

Tomando como referencia el estándar IEEE 829-1983, la documentación mínima que se debe generar durante la fase de pruebas de un ciclo de vida del software es:

1.- Plan de pruebas.

2.- Especificación de los requerimientos para el diseño de los casos de prueba.

3.- Caso de prueba, que incluye, además, la descripción del procedimiento de prueba y al descripción de ítem a probar (véase Capítulo 8).

4.- Reporte de incidentes de prueba.

5.- Resumen de pruebas.

Basándose nuevamente en al definición del IEEE Standard Glossary of Software Engineering Technology, un plan de pruebas es un documento que describe el alcance, enfoque, recursos y planificación de las actividades de prueba deseadas. Identifica los elementos y características a probar, las tareas de prueba, quién realizará cada tarea y cualquier riesgo que requiera planes de contingencia. Cabe destacar que, a pesar de ser un documento que se utiliza en la fase de pruebas, el plan de pruebas debería escribirse en la etapa de diseño, que es cuando se especifíca la arquiectura del sistema y se establecen y detallan los módulos/objetos que van a integrar el sistema. En este momento es mucho más fácil realizar un diseño de los casos de prueba y definir el plan de pruebas.

Seguidamente se lista y se explica un ejemplo estándar del índice de un plan de pruebas:

1.- Introducción al documento

2.- Alcance de la fase de pruebas

3.- Requisitos del entorno de pruebas (hardware y software)

4.- Ítems a probar

5.- Planificación de las pruebas

5.1.- Calendario

5.2.- Equipo de pruebas

5.3.- Responsabilidades (para cada una de las tareas previstas en el plan)

5.4.- Manejo de riesgos (identificación de riesgos y planes de contigencia)

5.5.- Técnicas

5.6.- Estrategía de integración utilizada

6.- Para cada paso de integración

6.1.- Orden de integración

6.2.- Módulos a ser probados

6.3.- Pruebas de unidad para los módulos a ser probados

6.4.- Resultados esperados

6.5.- Entorno de pruebas

7.- Resultados de las pruebas de verificación

7.1.- Datos

7.2.- Condiciones

8.- Resultados de las pruebas de validación

9.- Pruebas de estrés

10.- Monitorización de las pruebas

11.- Referencias y apéndices 

OOP - COHESION Y ACOPLAMIENTO

Acoplamiento y cohesión

El acoplamiento es una medida de la interconexión entre los módulos de un programa. El diseño es la fase en la que se puede y debe tener en cuenta esta medida. Así, hay que tender a un bajo acoplamiento, ya que, entre otras cosas, se minimiza el efecto onda (propagación de errores), se minimiza el riesgo al coste de cambiar un módulo por otro y se facilita el entendimiento del programa.

La cohesión mide la relación, principalmente funcional pero no sólo, de los elementos de un módulo. Hay que conseguir un alto grado de cohesión ya que conlleva un menor coste de programación y consecuentemente una mayor calidad del producto.

En definitiva, hay que diseñar haciendo que los módulos sean tan independientes como sea posible (bajo acoplamiento) y que cada módulo haga (idealmente) una sola función (alta cohesión).

Ambas medidas tienen una gran repercusión en las pruebas, ya que facilitan las mismas tanto a la hora de detección de un error, como a la hora de corregirlo y realizar las correspondientes pruebas de regresión.


 

SPRING JPA - HERENCIA

 

Herencia


En el caso de herencia, se puede utilizar una serie de anotaciones para indicar cómo se quiere tratar. Se utilizará como ejemplo una serie de clases: Step y sus clases hijas SimpleStep y MultipleStep.

Cuando una serie de objetos comparten herencia, se puede apreciar que, normalmente, no contienen los mismos datos. Es por esto que no se pueden almacenar todas las clases en una misma tabla. Sabiendo esto, hay tres distintas opciones que se pueden utilizar:

1.- Utilizar una tabla única para todas las clases, dejando vacíos los campos que no son propios de la clase de la que se trata. Esto puede producir una gran cantidad de espacio reservado innecesario en muchos casos, pero es viable cuando los atributos de las clases prácticamente no varían. Debe utilizar un discriminador para distinguir la clase de la que se trata en cada registro. El discriminador almacena el nombre de la clase para poder generar un objeto de la clase adecuada cuando se requiera.

2.- Utilizar una tabla para cada clase. En este caso, el espacio reservado siempre será adecuado y se puede distinguir la clase sin necesidad de un discriminador. Por otra parte, puede complicar peticiones como búsquedas conjuntas.

3.- Utilizar una tabla únia para datos comunes y una tabla específica de cada clase para el resto. Es el caso en el que los atributos de la clase padre se comparten y los datos específicos se almacenan en distintas tablas. También requiere un discriminador.

Con estos tres casos se cubren todas las posibilidades, la decisión depende de la naturaleza de los datos de cada clase. Una vez tomada la decisión, la implementación es simple ya que sólo debe añadirse la anotación @Inheritance indicanod la estrategía (por defecto SINGLE_TABLE) y en caso de que sea necesario indicar un nombre para la columna del discriminador mediante la anotación @DiscriminatorColumn.


@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "disc")
@Table(name = "step")public abstract class Step {

...

}

Para las clases hijas no es necesario realizar ningún cambio, basta con que estén anotadas como entidades tambén y que hereden de la clase padre como es debido.






BIG DATA

 Hoy en día, en cambio, la recogida de datos masivos ha permitido

obtener información sobre la muestra completa (o casi)

de datos relacionada con el fenómeno que hay que evaluar, es

decir, toda la población. Por ejemplo, si una institución desea

analizar los tweets que tratan sobre un tema de interés público,

es perfectamente factible que pueda recoger todos aquellos

que hablen del tema y analizarlos. En este caso, el análisis no

pretende confirmar o invalidar una hipótesis, sino establecer

correlaciones entre distintas variables de la muestra. Por

ejemplo, supongamos que existe una fuerte correlación entre

el lugar de residencia de los vecinos de una ciudad y su opinión

ante una determinada problemática de esta. En este caso, podemos

explotar la relación que existe entre ambas variables

aunque no sepamos la causa que induce de la una a la otra.

Los datos masivos imponen un nuevo paradigma donde la

correlación «sustituye» a la causalidad. Determinar la causalidad

de un fenómeno pierde importancia, y en contraposición,

«descubrir» las correlaciones entre las variables se convierte

en uno de los objetivos principales del análisis.

Este cambio de paradigma provoca que los sistemas de big

data se centren en encontrar «qué» aspectos están relacionados

entre sí, y no en «por qué» están relacionados. Estos

sistemas pretenden responder cuestiones del tipo: ¿qué pasó?,

¿qué está pasando? y ¿qué pasaría si?, pero desde un punto de

vista basado en las correlaciones, donde no se busca la explicación

del fenómeno, sino solo el descubrimiento del fenómeno

en sí. En consecuencia, la causalidad pierde terreno a favor de

asociación entre hechos.


Habéis entendido algo... YO NO

Una aproximación a DDD - Parte I

 Diseño guiado por el dominio (DDD)

El diseño guiado por el dominio (DDD) es un enfoque para el desarrollo de software que propone un modelado rico, expresivo y evolutivo basado en la realidad del negocio. El dominio representa lo que hace una organización y la forma en que lo hace.

Con esta aproximación los expertos del dominio y los desarrolladores se sitúan en el mismo nivel empleando un lenguaje ubicuo. No hace falta ninguna traducción de términos entre ellos porque todos hablan un lenguaje común, que se plasma hasta en el código de programación. No es necesario que el lenguaje siga los estándares de la industria que representa: utiliza los términos y acciones que en el negocio se dan.

El lenguaje ubicuo que se usa crece y cambia con el paso del tiempo. Nadie es capaz de conocer el dominio de un negocio completo porque este forma parte de un proceso de descubrimiento continuo. Si la organización sigue una estrategia de desarrollo ágil, en cada iteración se refina el modelo de forma incremental y este plasma en todo momento el software en funcionamiento.

Para su tratamiento, las áreas independientes del dominio se transforman en contextos delimitados. Cada contexto delimitado es un límite explícito que tiene su propio lenguaje ubicuo. Un concepto tiene un significado dentro de un contexto delimitado, pero fuera de él puede tener un significado totalmente distinto. No se puede tratar de incluir todos los conceptos en un único contexto: se deben separar los conceptos en diferentes contextos y entender las diferencias que existen para un concepto llamado igual en uno y otro contexto.

¿Te has enterado de algo?, YO NO...

PRINCIPOS SOLID - ESQUEMATIZADO - SIN EJEMPLOS

S.O.L.I.D.

1.- SOLID es el acronimo qeu acuño Michael Feathers, basándose en los 5 principios de al programación orientada a objetos que Robert C. Martin había recopilado en el año 2000 en su paper "Design Principles and Dsign Patterns".

2.- Los objetivos de estos 5 principios a la hora de escribir código son:

a.- Crear un software eficaz: que cumpla con su cometido y que sea robusto y estable.

b.- Escribir un código limpio y flexible ante los cambios: que se pueda modificar fácilmente según necesidad, que sea reutilizable y mantenible.

c.- Permitir escalabilidad: que acepte ser ampliado con nuevas funcionalidades de manera ágil.

3.- La aplicación de los principios SOLID está muy relacionada con la comprensión y el uso de patrones de diseño, que permitirán minimizar el acoplamiento (grado de interdependencia que tienen dos unidades de software entre sí) y maximizar la cohesión (grado en que elementos diferentes de un sistema permanecen unidos para alcanzar un mejor resultado que si trabajaran por separado).

S.O.L.I.D.

S

Single Responsability Principle (SRP)

Principio de responsabilidad única

O

Open/Closed Principle (OCP)

Principio de abierto-cerrado

L

Liskov Substitution Principle (LSP)

Principio de sustitución de Liskov

I

Interface Segretation Principle (ISP)

Principios de segregación de interfaces

D

Dependency Inversion Principle (DIP)

Principio de inversión de dependencias

1.- Principio de Responsabilidad Única

a.- La S del acrónimo del que hablamos hoy se refiere a Single Responsability Principle (SRP). Según este principio "una clase debería tener una, y solo una, razón para cambiar".

Es esto precisamente, "razón para cambiar", lo que Robert C. Martin identifica como "responsabilidad".

b.- El principio de Responsabilidad Única es el más importante y fundamental de SOLID, muy sencillo de explicar, pero el más difícil de seguir en la práctica.

c.- El propio Bob resume cómo hacerlo: "Reúne las cosas que ambian por las mismas razones. Separa aquellas que cambian por razones diferentes".

2.- Principio de Abierto/Cerrado

a.- El segundo principio de SOLID lo formuló Bertrand Meyer en 1988 en su libro "Object Oriented Software Construction" y dice: "Deberías ser capaz de extender el comportamiento de una clase, sin modificarla" En otras palabras: las clases que usas deberían estar abiertas para poder extenderse y cerradas para modificarse.

b.- En su blog Robert C. Martin defendió este principio que a priori puede parecer una paradoja.

c.- Es importante tener en cuenta el Open/Closed Principle (OCP) a la hora de desarrollar clases, librerías, frameworks, microservicios.

3.- Principio de Sustitución de Liskov

a.- La L de SOLID alude al apellido de quien lo creó, Barbara Liskov, y dice que "las clases derivadas deben poder sustituirse por sus clases base".

b.- Esto significa que los objetos deben poder ser reemplazados por instancias o lo que es lo mismo: si en un programa utilizamos cierta clase, deberíamos poder usar cualquiera de sus subclases sin interferir en la funcionalidad del programa.

c.- Según Robert. C. Martin incumplir el Liskov Principle Subsitution Principle (LSP) implica violar también el principio de Abierto/Cerrado.

4.- Principio de Segregación de la Interfaz

a.- En el cuarto principio de SOLID, el tío Bob sugiere: "Haz interfaces que sean específicas para un tipo de cliente", es decir, para una finalidad concreta.

b.- En este sentido, según el Interface Segregation Principle (ISP), es preferible contar con muchas interfaces que definan pocos métodos que tener una interface forzada a implementar muchos métodos a los que no dará uso.

5.- Principio de Inversión de Dependencias

a.- Legamos al último principio: "Depende de abstracciones, no de clases concretas".

b.- Así, Robert C. Martin recomienda:

1.- Los módulos de alto nivel no deberían depender de módulos de bajo nivel. Ambos deberían depender de abstracciones.

2.- Las abstracciones no deberían depender de los detalles. Los detalles deberían depender de las abstracciones.

3.- El objetivo del Dependency Inversion Principle (DIP) consiste en reducir las dependencias entre los módulos del código, es decir, alcanzar un bajo acoplamiento de las clases.


Contenido desarrollo de software - Arquitectura Software

ENUM en JAVA