Estilo de código Java de AOSP para colaboradores

Los estilos de código de esta página son reglas estrictas para contribuir con código Java al Proyecto de código abierto de Android (AOSP). Las contribuciones a la plataforma Android que no se adhieren a estas reglas generalmente no son aceptadas. Reconocemos que no todo el código existente sigue estas reglas, pero esperamos que todo el código nuevo las cumpla. Consulta Coding with Respect para ver ejemplos de la terminología que debes usar y evitar para un ecosistema más inclusivo.

Sé coherente

Una de las reglas más sencillas es SER COHERENTE. Si estás editando código, tómate unos minutos para mirar el código circundante y determinar su estilo. Si ese código utiliza espacios alrededor de las cláusulas if, tú también deberías hacerlo. Si los comentarios del código tienen pequeñas cajas de estrellas a su alrededor, haz que tus comentarios también tengan pequeñas cajas de estrellas a su alrededor.

El objetivo de tener directrices de estilo es tener un vocabulario común de codificación, para que los lectores puedan concentrarse en lo que estás diciendo, en lugar de en cómo lo estás diciendo. Aquí presentamos reglas de estilo globales para que conozcas el vocabulario, pero el estilo local también es importante. Si el código que añades a un archivo tiene un aspecto drásticamente diferente del código existente a su alrededor, los lectores perderán el ritmo al leerlo. Intenta evitar esto.

Reglas del lenguaje Java

Android sigue las convenciones de codificación estándar de Java con las reglas adicionales que se describen a continuación.

No ignore las excepciones

Puede ser tentador escribir código que ignore una excepción, como por ejemplo:

 void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { } }

No haga esto. Si bien puede pensar que su código nunca se encontrará con esta condición de error o que no es importante manejarla, ignorar este tipo de excepción crea minas en su código para que alguien más las active algún día. Debes manejar cada excepción en tu código de una manera principista; el manejo específico varía dependiendo del caso.

«Cada vez que alguien tiene una cláusula catch vacía debe tener una sensación espeluznante. Definitivamente hay veces en las que realmente es lo correcto, pero al menos tienes que pensar en ello. En Java no puedes escapar de la sensación espeluznante». – James Gosling

Las alternativas aceptables (por orden de preferencia) son:

  • Lanzar la excepción hasta el llamador de tu método.
     void setServerPort(String value) throws NumberFormatException { serverPort = Integer.parseInt(value); }
  • Lanzar una nueva excepción adecuada a tu nivel de abstracción.
     void setServerPort(String value) throws ConfigurationException { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { throw new ConfigurationException("Port " + value + " is not valid."); } }
  • Maneja el error con gracia y sustituye un valor apropiado en el bloque catch {}
     /** Set port. If value is not a valid number, 80 is substituted. */ void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { serverPort = 80; // default port for server } }
  • Captura la excepción y lanza una nueva instancia de RuntimeException. Esto es peligroso, así que hazlo sólo si estás seguro de que si se produce este error, lo apropiado es estrellarse.
     /** Set port. If value is not a valid number, die. */ void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { throw new RuntimeException("port " + value " is invalid, ", e); } }
  • Como último recurso, si estás seguro de que ignorar la excepción es apropiado, entonces puedes ignorarla, pero también debes comentar por qué con una buena razón.
    /** If value is not a valid number, original port number is used. */void setServerPort(String value) { try { serverPort = Integer.parseInt(value); } catch (NumberFormatException e) { // Method is documented to just ignore invalid user input. // serverPort will just be unchanged. }}

No cojas excepciones genéricas

Puede ser tentador ser perezoso a la hora de coger excepciones y hacer algo así:

 try { someComplicatedIOFunction(); // may throw IOException someComplicatedParsingFunction(); // may throw ParsingException someComplicatedSecurityFunction(); // may throw SecurityException // phew, made it all the way } catch (Exception e) { // I'll just catch all exceptions handleError(); // with one generic handler! }

No hagas esto. En casi todos los casos, es inapropiado atrapar Exception genéricos o Throwable (preferiblemente no Throwable porque incluye Error excepciones). Es peligroso porque significa que las excepciones que no esperabas (incluyendo las excepciones en tiempo de ejecución como ClassCastException) son atrapadas en el manejo de errores a nivel de aplicación. Oculta las propiedades de manejo de fallos de tu código, lo que significa que si alguien añade un nuevo tipo de excepción en el código que estás llamando, el compilador no te indicará que necesitas manejar el error de forma diferente. En la mayoría de los casos no deberías manejar diferentes tipos de excepciones de la misma manera.

La rara excepción a esta regla es el código de prueba y el código de alto nivel donde se quiere atrapar todo tipo de errores (para evitar que aparezcan en una interfaz de usuario, o para mantener un trabajo por lotes en funcionamiento). En estos casos, puede atrapar el Exception genérico (o Throwable) y manejar el error adecuadamente. Eso sí, piénsalo bien antes de hacerlo y pon comentarios explicando por qué es seguro en este contexto.

Alternativas a la captura de excepciones genéricas:

  • Atrapa cada excepción por separado como parte de un bloque de captura múltiple, por ejemplo:
    try { ...} catch (ClassNotFoundException | NoSuchMethodException e) { ...}
  • Refactoriza tu código para tener un manejo de errores más fino, con múltiples bloques try. Dividir el IO del parsing, y manejar los errores por separado en cada caso.
  • Retire la excepción. Muchas veces no necesitas atrapar la excepción a este nivel de todos modos, simplemente deja que el método la lance.
    • ¡Recuerda que las excepciones son tus amigas! Cuando el compilador se queje de que no estás atrapando una excepción, no frunzas el ceño. Sonríe. El compilador acaba de facilitarte la captura de problemas en tiempo de ejecución en tu código.

      No utilices finalizadores

      Los finalizadores son una forma de hacer que un trozo de código se ejecute cuando un objeto se recoge de la basura. Mientras que los finalizadores pueden ser útiles para la limpieza (en particular de los recursos externos), no hay garantías en cuanto a cuando un finalizador será llamado (o incluso que será llamado en absoluto).

      Android no utiliza finalizadores. En la mayoría de los casos, puede utilizar un buen manejo de excepciones en su lugar. If you absolutely need a finalizer, define a close() method (or the like) and document exactly when that method needs to be called (see InputStream for an example). In this case, it’s appropriate but not required to print a short log message from the finalizer, as long as it’s not expected to flood the logs.

      Fully qualify imports

      When you want to use class Bar from package foo, there are two possible ways to import it:

      • import foo.*;

        Potentially reduces the number of import statements.

      • import foo.Bar;

        Makes it obvious what classes are used and the code is more readable for maintainers.

      Use import foo.Bar; for importing all Android code. An explicit exception is made for Java standard libraries (java.util.*java.io.*, etc.) and unit test code (junit.framework.*).

      Reglas de las bibliotecas Java

      Existen convenciones para el uso de las bibliotecas y herramientas Java de Android. En algunos casos, la convención ha cambiado de manera importante y el código más antiguo podría utilizar un patrón o biblioteca obsoleta. Cuando se trabaja con dicho código, está bien continuar con el estilo existente. Sin embargo, cuando crees nuevos componentes, nunca utilices bibliotecas obsoletas.

      Reglas de estilo de Java

      Cada archivo debe tener una declaración de copyright en la parte superior, seguida de las declaraciones de paquete e importación (cada bloque separado por una línea en blanco), y finalmente la declaración de clase o interfaz. En los comentarios de Javadoc, describa lo que hace la clase o interfaz.

/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.android.internal.foo;import android.os.Blah;import android.view.Yada;import java.sql.ResultSet;import java.sql.SQLException;/** * Does X and Y and provides an abstraction for Z. */public class Foo { ...}

Cada clase y método público no trivial que escribas debe contener un comentario Javadoc con al menos una frase que describa lo que hace la clase o el método. Esta frase debe comenzar con un verbo descriptivo en tercera persona.

Ejemplos

/** Returns the correctly rounded positive square root of a double value. */static double sqrt(double a) { ...}

o

/** * Constructs a new String by converting the specified array of * bytes using the platform's default character encoding. */public String(byte bytes) { ...}

No necesitas escribir Javadoc para métodos get y set triviales como setFoo() si todo lo que diría tu Javadoc es «establece Foo». Si el método hace algo más complejo (como imponer una restricción o tiene un efecto secundario importante), entonces debes documentarlo. Si no es obvio lo que significa la propiedad «Foo», debes documentarlo.

Cada método que escribas, público o no, se beneficiaría de Javadoc. Los métodos públicos son parte de una API y por lo tanto requieren Javadoc. Android no impone un estilo específico para escribir los comentarios de Javadoc, pero deberías seguir las instrucciones de Cómo escribir comentarios de Doc para la herramienta Javadoc.

Escribe métodos cortos

Cuando sea posible, mantén los métodos pequeños y centrados. Reconocemos que los métodos largos son a veces apropiados, por lo que no se pone un límite duro a la longitud del método. Si un método supera las 40 líneas más o menos, piense si se puede dividir sin dañar la estructura del programa.

Defina los campos en lugares estándar

Defina los campos en la parte superior del archivo o inmediatamente antes de los métodos que los utilizan.

Limitar el alcance de las variables

Mantener el alcance de las variables locales al mínimo. Esto aumenta la legibilidad y la mantenibilidad de su código y reduce la probabilidad de error. Declare cada variable en el bloque más interno que encierra todos los usos de la variable.

Declare las variables locales en el punto donde se utilizan por primera vez. Casi todas las declaraciones de variables locales deben contener un inicializador. Si todavía no tiene suficiente información para inicializar una variable con sentido, posponga la declaración hasta que la tenga.

La excepción son las declaraciones try-catch. Si una variable se inicializa con el valor de retorno de un método que lanza una excepción comprobada, debe inicializarse dentro de un bloque try. If the value must be used outside of the try block, then it must be declared before the try block, where it can’t yet be sensibly initialized:

// Instantiate class cl, which represents some sort of SetSet s = null;try { s = (Set) cl.newInstance();} catch(IllegalAccessException e) { throw new IllegalArgumentException(cl + " not accessible");} catch(InstantiationException e) { throw new IllegalArgumentException(cl + " not instantiable");}// Exercise the sets.addAll(Arrays.asList(args));

However, you can even avoid this case by encapsulating the try-catch block in a method:

Set createSet(Class cl) { // Instantiate class cl, which represents some sort of Set try { return (Set) cl.newInstance(); } catch(IllegalAccessException e) { throw new IllegalArgumentException(cl + " not accessible"); } catch(InstantiationException e) { throw new IllegalArgumentException(cl + " not instantiable"); }}...// Exercise the setSet s = createSet(cl);s.addAll(Arrays.asList(args));

Declare loop variables in the for statement itself unless there’s a compelling reason to do otherwise:

for (int i = 0; i < n; i++) { doSomething(i);}

and

for (Iterator i = c.iterator(); i.hasNext(); ) { doSomethingElse(i.next());}

Order import statements

The ordering of import statements is:

  1. Android imports
  2. Imports from third parties (comjunitnetorg)
  3. java and javax

To exactly match the IDE settings, the imports should be:

  • Alfabéticos dentro de cada agrupación, con las mayúsculas antes de las minúsculas (por ejemplo, la Z antes de la a)
  • Separados por una línea en blanco entre cada agrupación mayor (androidcomjunitnetorgjavajavax)

Originalmente, no había ningún requisito de estilo en el ordenamiento, lo que significaba que los IDEs estaban siempre cambiando el ordenamiento o los desarrolladores de IDEs tenían que desactivar las características de gestión automática de las importaciones y mantenerlas manualmente. Esto se consideró malo. Cuando se preguntó por el estilo Java, los estilos preferidos variaban enormemente y se llegó a la conclusión de que Android debía simplemente «elegir un ordenamiento y ser coherente». Así que elegimos un estilo, actualizamos la guía de estilo e hicimos que los IDEs lo obedecieran. Esperamos que a medida que los usuarios de los IDEs trabajen en el código, las importaciones en todos los paquetes se ajusten a este patrón sin un esfuerzo de ingeniería adicional.

We chose this style such that:

  • The imports that people want to look at first tend to be at the top (android).
  • The imports that people want to look at least tend to be at the bottom (java).
  • Humans can easily follow the style.
  • IDEs can follow the style.

Put static imports above all the other imports ordered the same way as regular imports.

Use spaces for indentation

We use four (4) space indents for blocks and never tabs. When in doubt, be consistent with the surrounding code.

We use eight (8) space indents for line wraps, including function calls and assignments.

Recommended

Instrument i = someLongExpression(that, wouldNotFit, on, one, line);

Not recommended

Instrument i = someLongExpression(that, wouldNotFit, on, one, line);

Follow field naming conventions

  • Non-public, non-static field names start with m.
  • Static field names start with s.
  • Other fields start with a lower case letter.
  • Public static final fields (constants) are ALL_CAPS_WITH_UNDERSCORES.

For example:

public class MyClass { public static final int SOME_CONSTANT = 42; public int publicField; private static MyClass sSingleton; int mPackagePrivate; private int mPrivate; protected int mProtected;}

Use standard brace style

Put braces on the same line as the code before them, not on their own line:

class MyClass { int func() { if (something) { // ... } else if (somethingElse) { // ... } else { // ... } }}

We require braces around the statements for a conditional. Exception: If the entire conditional (the condition and the body) fit on one line, you may (but are not obligated to) put it all on one line. For example, this is acceptable:

if (condition) { body();}

and this is acceptable:

if (condition) body();

but this is not acceptable:

if (condition) body(); // bad!

Limit line length

Each line of text in your code should be at most 100 characters long. While much discussion has surrounded this rule, the decision remains that 100 characters is the maximum with the following exceptions:

  • Si una línea de comentario contiene un comando de ejemplo o una URL literal de más de 100 caracteres, esa línea puede tener más de 100 caracteres para facilitar el corte y pegado.
  • Las líneas de importación pueden superar el límite porque los humanos rara vez las ven (esto también simplifica la escritura de herramientas).

Utiliza anotaciones estándar de Java

Las anotaciones deben preceder a otros modificadores para el mismo elemento de lenguaje. Las anotaciones de marcador simples (por ejemplo, @Override) pueden aparecer en la misma línea con el elemento de lenguaje. Si hay múltiples anotaciones, o anotaciones parametrizadas, enumérelas una por línea en orden alfabético.

Las prácticas estándar de Android para las tres anotaciones predefinidas en Java son:

  • Utilice la anotación @Deprecated siempre que se desaconseje el uso del elemento anotado. Si utiliza la anotación @Deprecated, también debe tener una etiqueta @deprecated Javadoc y debe nombrar una implementación alternativa. Además, recuerda que un método @Deprecated debe seguir funcionando. Si ves código antiguo que tiene una etiqueta @deprecated Javadoc, añade la anotación @Deprecated.
  • Utiliza la anotación @Override siempre que un método sobrescriba la declaración o implementación de una superclase. Por ejemplo, si utiliza la etiqueta @inheritdocs Javadoc, y deriva de una clase (no de una interfaz), también debe anotar que el método anula el método de la clase padre.
  • Usa la anotación @SuppressWarnings sólo en circunstancias en las que sea imposible eliminar una advertencia. If a warning passes this «impossible to eliminate» test, the @SuppressWarnings annotation must be used, to ensure that all warnings reflect actual problems in the code.

    When a @SuppressWarnings annotation is necessary, it must be prefixed with a TODO comment that explains the «impossible to eliminate» condition. This normally identifies an offending class that has an awkward interface. Por ejemplo:

    // TODO: The third-party class com.third.useful.Utility.rotate() needs generics@SuppressWarnings("generic-cast")List<String> blix = Utility.rotate(blax);

    When a @SuppressWarnings annotation is required, refactor the code to isolate the software elements where the annotation applies.

Treat acronyms as words

Treat acronyms and abbreviations as words in naming variables, methods, and classes to make names more readable:

Good Bad
XmlHttpRequest XMLHTTPRequest
getCustomerId getCustomerID
class Html class HTML
String url String URL
long id long ID

As both the JDK and the Android code bases are inconsistent around acronyms, it’s virtually impossible to be consistent with the surrounding code. Therefore, always treat acronyms as words.

Use TODO comments for code that is temporary, a short-term solution, or good enough but not perfect. These comments should include the string TODO in all caps, followed by a colon:

// TODO: Remove this code after the UrlTable2 has been checked in.

y

// TODO: Change this to use a flag instead of a constant.

Si tu TODO es de la forma «En una fecha futura haz algo» asegúrate de que incluyes una fecha específica («Arreglar antes de noviembre de 2005») o un evento específico («Eliminar este código después de que todos los mezcladores de producción entiendan el protocolo V7»).

Loguear con moderación

Aunque el registro es necesario, tiene un impacto negativo en el rendimiento y pierde su utilidad si no se mantiene razonablemente conciso. Las instalaciones de registro proporcionan cinco niveles diferentes de registro:

  • ERROR: Se utiliza cuando ha ocurrido algo fatal, es decir, algo que tendrá consecuencias visibles para el usuario y que no será recuperable sin borrar algunos datos, desinstalar apps, borrar las particiones de datos o reflashear todo el dispositivo (o algo peor). Este nivel siempre se registra. Los problemas que justifican algún registro en el nivel ERROR son buenos candidatos para ser reportados a un servidor de recopilación de estadísticas.
  • WARNING: Se utiliza cuando ha sucedido algo grave e inesperado, es decir, algo que tendrá consecuencias visibles para el usuario pero que es probable que se pueda recuperar sin pérdida de datos realizando alguna acción explícita, desde esperar o reiniciar una app hasta volver a descargar una nueva versión de una app o reiniciar el dispositivo. Este nivel siempre se registra. Los problemas que justifican el registro en el nivel WARNING también podrían considerarse para informar a un servidor de recopilación de estadísticas.
  • INFORMATIVE: Se utiliza para anotar que ha ocurrido algo interesante, es decir, cuando se detecta una situación que puede tener un impacto generalizado, aunque no es necesariamente un error. Tal condición sólo debe ser registrada por un módulo que crea que es el más autorizado en ese dominio (para evitar la duplicación de registros por componentes no autorizados). Este nivel siempre se registra.
  • DEBUG: Se utiliza para anotar más lo que está sucediendo en el dispositivo que podría ser relevante para investigar y depurar comportamientos inesperados. Registra sólo lo necesario para reunir suficiente información sobre lo que ocurre con tu componente. Si sus registros de depuración están dominando el registro, entonces usted debe utilizar el registro verboso.

    Este nivel se registra incluso en las compilaciones de la versión, y se requiere que esté rodeado por un bloque if (LOCAL_LOG) o if LOCAL_LOGD), donde LOCAL_LOG se define en su clase o subcomponente, de modo que hay una posibilidad de desactivar todo ese registro. Por lo tanto, no debe haber ninguna lógica activa en un bloque if (LOCAL_LOG). Toda la construcción de cadenas para el registro también debe colocarse dentro del bloque if (LOCAL_LOG). No refactorice la llamada al registro en una llamada a un método si va a hacer que la construcción de la cadena tenga lugar fuera del bloque if (LOCAL_LOG).

    Hay algún código que todavía dice if (localLOGV). Esto se considera aceptable también, aunque el nombre no es estándar.

  • VERBOSE: Utilizar para todo lo demás. Este nivel sólo se registra en las construcciones de depuración y debe estar rodeado por un bloque if (LOCAL_LOGV) (o equivalente) para que pueda ser compilado por defecto. Cualquier cadena de construcción es despojada de las construcciones de liberación y necesita aparecer dentro del bloque if (LOCAL_LOGV).

Notas

  • Dentro de un módulo dado, que no sea a nivel de VERBOSE, un error sólo debe ser reportado una vez si es posible. Dentro de una única cadena de llamadas a funciones dentro de un módulo, sólo la función más interna debería devolver el error, y las llamadas en el mismo módulo sólo deberían añadir algún registro si eso ayuda significativamente a aislar el problema.
  • En una cadena de módulos, aparte del nivel VERBOSE, cuando un módulo de nivel inferior detecta datos no válidos procedentes de un módulo de nivel superior, el módulo de nivel inferior sólo debería registrar esta situación en el registro DEBUG, y sólo si el registro proporciona información que no está disponible de otro modo para la persona que llama. Específicamente, no hay necesidad de registrar situaciones en las que se lanza una excepción (la excepción debe contener toda la información relevante), o donde la única información que se registra está contenida en un código de error. Esto es especialmente importante en la interacción entre el framework y las aplicaciones, y las condiciones causadas por las aplicaciones de terceros que son manejadas adecuadamente por el framework no deberían activar el registro más allá del nivel DEBUG. Las únicas situaciones que deberían activar el registro en el nivel INFORMATIVE o superior es cuando un módulo o app detecta un error en su propio nivel o procedente de un nivel inferior.
  • Cuando una condición que normalmente justificaría algún tipo de registro es probable que ocurra muchas veces, puede ser una buena idea implementar algún mecanismo de limitación de la tasa para evitar el desbordamiento de los registros con muchas copias duplicadas de la misma (o muy similar) información.
  • Las pérdidas de conectividad de la red se consideran comunes y son totalmente esperables, y no deberían registrarse gratuitamente. Una pérdida de conectividad de red que tenga consecuencias dentro de una app debe ser registrada en el nivel DEBUG o VERBOSE (dependiendo de si las consecuencias son lo suficientemente graves e inesperadas como para ser registradas en una build de lanzamiento).
  • Tener un sistema de archivos completo en un sistema de archivos accesible para o en nombre de aplicaciones de terceros no debería registrarse a un nivel superior a INFORMATIVO.
  • Los datos no válidos procedentes de cualquier fuente no fiable (incluyendo cualquier archivo en el almacenamiento compartido, o los datos que vienen a través de una conexión de red) se consideran esperados y no deben desencadenar ningún registro a un nivel superior a DEBUG cuando se detecta que no son válidos (e incluso entonces el registro debe ser lo más limitado posible).
  • Cuando se utiliza en objetos String, el operador + crea implícitamente una instancia StringBuilder con el tamaño de búfer por defecto (16 caracteres) y potencialmente otros objetos temporales String. Así que crear explícitamente objetos StringBuilder no es más caro que confiar en el operador por defecto + (y puede ser mucho más eficiente). Ten en cuenta que el código que llama a Log.v() se compila y ejecuta en las construcciones de lanzamiento, incluyendo la construcción de las cadenas, incluso si los registros no se están leyendo.
  • Cualquier registro que esté destinado a ser leído por otras personas y a estar disponible en las compilaciones de lanzamiento debe ser conciso sin ser críptico, y debe ser comprensible. Esto incluye todos los registros hasta el nivel DEBUG.
  • Cuando sea posible, mantenga el registro en una sola línea. Las longitudes de línea de hasta 80 o 100 caracteres son aceptables. Evite longitudes superiores a unos 130 o 160 caracteres (incluyendo la longitud de la etiqueta) si es posible.
  • Si el registro informa de los éxitos, nunca lo utilice en niveles superiores a VERBOSE.
  • Si está utilizando el registro temporal para diagnosticar un problema difícil de reproducir, manténgalo en el nivel DEBUG o VERBOSE y enciérrelo con bloques if que permitan desactivarlo en tiempo de compilación.
  • Tenga cuidado con las fugas de seguridad a través del registro. Evite registrar información privada. En particular, evite registrar información sobre contenido protegido. Esto es especialmente importante cuando se escribe código de framework, ya que no es fácil saber de antemano qué será y qué no será información privada o contenido protegido.
  • No utilizar nunca System.out.println() (o printf() para el código nativo). System.out y System.err se redirigen a /dev/null, por lo que sus declaraciones de impresión no tienen efectos visibles. Sin embargo, toda la construcción de cadenas que sucede para estas llamadas todavía se ejecuta.
  • La regla de oro del registro es que tus registros no pueden empujar innecesariamente otros registros fuera del buffer, así como otros no pueden empujar los tuyos.

Reglas de estilo de Javatests

Sigue las convenciones de nomenclatura de métodos de prueba y utiliza un guión bajo para separar lo que se está probando del caso específico que se está probando. Este estilo hace más fácil ver qué casos se están probando. For example:

testMethod_specificCase1 testMethod_specificCase2void testIsDistinguishable_protanopia() { ColorMatcher colorMatcher = new ColorMatcher(PROTANOPIA) assertFalse(colorMatcher.isDistinguishable(Color.RED, Color.BLACK)) assertTrue(colorMatcher.isDistinguishable(Color.X, Color.Y))}

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *