Herramientas java Joaquín Salvachúa Tomas Robles -1- © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Desarrollo java Necesidad de herramientas de desarrollo. Utilidades 4Construir programas. 4Automatizar pruebas. 4Facilidades de trazado. Entornos integrados: 4Pesados: matar moscas a cañonazos. 4Caros: • Excepto netbeans: http://www.netbeans.org • Gratis pero hace falta memoria (>= 128 Mb) -2- © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Herramientas proporcionadas Código de dominio publico de la mayor calidad: 4Construcción de programas: • ANT 4Prueba de programas: • JUNIT 4Gestión de trazas y LOGS: • LOG4J -3- © Tomás Robles & Joaquín Salvachúa 2005 dit UPM ANT -4- © Tomás Robles & Joaquín Salvachúa 2005 dit UPM ¿Que es ANT ? Plataforma para la construcción de programas (equivalente a make y makefiles). Portable, totalmente escrito en java: Independiente de la plataforma. Mejora ciertas características de make: ficheros de configuración XML. Código abierto (parte del proyecto jakarta de apache). Posibilidad de realizar scripts sencillos -5- © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Utilidad Independiente de la plataforma 4 Solo requiere una JVM > 1.1 4 Independiente de maquina (windows, unix, mac). No importan path o retornos de carro. Fácil de utilizar 4 Incluye facilidades típicas de construcción de programas. 4 Disponibles tareas encontradas útiles por usuarios. 4 Elimina ciertos detalles crípticos de make. Fácil de extender 4 Crear una nueva tarea es tan sencillo como heredar una clase y añadir el comportamiento deseado. Estándar de facto en programas Java. -6- © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Estructura de un fichero ant Project 4Una colección de objetivos de alto nivel. Property 4Una variable de ant: usado para configurar. Target 4Un conjunto de tareas a ejecutar para conseguir un cierto objetivo. Task 4Una unidad de ejecución (cada paso). -7- © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Funcionamiento Existe un fichero con el proyecto en la raíz (build.xml). Cada fichero contiene uno o mas objetivos (target) Cada objetivo se ejecuta: 4Por que el proyecto depende de el 4Se indica el nombre por línea de comandos. Cada tarea se ejecuta (si es necesaria) una sola vez. Algunas tareas pueden ser condicionales. -8- © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Estructura típica de directorios project 4 README files, build.xml, etc. 4 classes • ficheros. .class 4 doc • Documentación del proyecto • api – Ficheros javadoc generados 4 docroot • Ficheros necesarios para aplicaciones web (HTML, JSP, XML, etc): 4 lib • Ficheros JAR con librerías necesarias para el proyecto. 4 Src • Código fuente del proyecto -9- © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Revisión rápida de XML Comenzamos con la línea: <?xml version="1.0" encoding="UTF-8"?> Las etiquetas van entre < y > y finalizan con / <tag>body</tag> or <tag/> Las etiquetas distinguen mayúsculas y minúsculas (distinto de HTML). Las etiquetas pueden ser autocontenidas <tag attribute="value"/> Los valores y las strings tienen que ir entre comillas. - 10 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Etiqueta Project <project name="MyProject" default="dist" basedir="."> ... </project> Objetivo principal. Indica que tareas son obligatorias. Donde esta el código: 4Uso de paths relativos para evitar problemas. - 11 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Etiqueta Target <target name="dist" depends="init" description="Makes a distribution" if="code-present" unless="time-is-short"> ... </target> Objetivo a alcanzar. Obligatorio el nombre (“name”) de la tarea. Puede depender de otras que han de completarse antes. El resto de campos son opcionales. - 12 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Algunas referencias a ficheros Pattern-sets <patternset id="my.pattern"> <include name="**/*.java"/> <exclude name="**/*Test*"/> </patternset> File-sets <fileset dir="./source"> <patternset refid="my.pattern“/> </fileset> - 13 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Un build.xml sencillo <?xml version="1.0" encoding="UTF-8"?> <project name="Test" default="dist" basedir="."> <target name="dist"> <javac srcdir="."/> </target> </project> Mínimo fichero que compila todos los .java de un directorio recursivamente. - 14 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Tareas incorporadas Ant Echo AntCall Exec AntStructure ExecOn Apply Fail Available Filter Chmod FixCRLF Copy GenKey Cvs Get Delete GUnzip - 15 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Tareas incorporadas (II) Gzip Property Jar Replace Java Rmic Javac SignJar Javadoc Sql Mail Style Mkdir Tar Move Taskdef Patch Touch - 16 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Tareas incorporadas (III) Tstamp Unjar Untar Unwar Unzip Uptodate War Zip - 17 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Tareas Opcionales ANTLR JUnitReport Cab Native2Ascii Depend PropertyFile FTP RenameExtensions JavaCC Script Javah Sound JJTree Stylebook Jlink Telnet JUnit Test - 18 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Instalación en Windows Verificar instalación de java. Poner variables: 4JAVA_HOME a donde este instalado el JDK: • Como C:\jdk1.4 4Añadir al CLASSPATH • Ant.jar y xerces.jar 4Añadir al PATH • %ANT_HOME%\bin Verificar documentación. - 19 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Pantalla Indica las tareas que va ejecutando: 4 Ejemplo: Searching for build.xml ... Buildfile: C:\XMLProgLabs\Framework\build.xml prepare: [mkdir] Created dir: C:\XMLProgLabs\Framework\classes compile: [javac] Compiling 26 source files to C:\XMLProgLabs\Framework\classes war: [war] Building war: C:\XMLProgLabs\Framework\shopping.war undeploy: [delete] Deleting directory C:\Tomcat\webapps\shopping [delete] Deleting: C:\Tomcat\webapps\shopping.war deploy: [copy] Copying 1 files to C:\Tomcat\webapps BUILD SUCCESSFUL Total time: 5 seconds - 20 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Recursos http://jakarta.apache.org/ant/ 4Pagina principal de ant http://jakarta.apache.org/ant/manual/index.ht ml 4Manual en línea de ANT (normalmente suficiente editar uno existente). http://jakarta.apache.org/ant/resources.html 4Artículos, presentaciones y otros. - 21 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM JUnit - 22 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Outline Unit Testing 4Testing against Contract 4Writing Unit Tests 4Using Test Harnesses Introduction to JUnit 4Origins of JUnit 4Desing og JUnit JUnit How to - 23 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Unit Testing Roughly equivalent to chip-level testing for hardware Its testing done to each module, in isolation, to verify its behavior Typically the unit test will establish some sort of artificial environment and then invoke routines in the module being tested It then checks the results returned against either some known value or against the results from previous runs of the same test (regression testing) When the modules are assembled we can use the same tests to test the system as a whole - 24 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Testing against Contract When we write unit tests we want to write test cases that ensure a given unit honors its contract 4This will tell us whether the code meets the contract and whether the contract means what we think it means i Contract for square root routine /* * @pre argument >= 0 * @post abs((result*result)-argument)<epsilon */ - 25 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Testing against Contract The above contract tells us what to test: 4Pass in a negative argument and ensure that it is rejects 4Pass in an argument of zero to ensure that it is accepted (this is a boundary value) 4Pass in values between zero and the maximum expressible argument and verify that the difference between the square of the result and the original argument is less than some value epsilon - 26 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Testing against Contract When you design a module or even a single routine, you should design both its contract and the code to test that contract By designing code to pass a test and fulfill its contract, you might consider boundary conditions and other issues that you wouldn't consider otherwise The best way to fix errors is to avoid them in the first place By building the tests before you implement the code you get to try out the interface before you commit to it - 27 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Writing Unit Tests Unit test should be conveniently located 4 For small projects you can imbed the unit test for a module in the module itself 4 For larger projects you should keep the tests in the package directory or a /test subdirectory of the package By making the code accessible to developers you provide them with: 4 Examples of how to use all the functionality of your module 4 A means to build regression tests to validate any future changes to the code In Java, you can use the main routine to run your unit tests - 28 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Using Test Harnesses A test harness can handle common operations such as 4Logging status 4Analyzing output for expected results 4Selecting and running the tests Harnesses can be: 4GUI driven 4Written in the same language as the rest of the project 4May be implemented as a combination of make files and scripts - 29 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Using Test Harnesses A test harness should include the following capabilities: 4A standard way to specify setup and cleanup 4A method for selecting individual tests or all available tests 4A means of analyzing output for expected (or unexpected) results 4A standardized form of failure reporting Tests should be composable: that is, a test can be composed of subtests of subcomponents to any depth - 30 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Introduction to JUnit This short primer demonstrates how to write and run simple test cases and test suites using the JUnit testing framework - 31 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Origins of JUnit Created by Erich Gamma and Kent Beck using paired programming. Rewrite Kent’s SmallTalk framework. JUnit version 1.0 was released March 1998. The current version 3.2 was released in January 2000. - 32 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM JUnit Goals Provide hope that developers will actually write tests – write your tests first Create Tests that have value over time. Leverage existing tests to create new ones – setting up a “fixture” - 33 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Why Use JUnit? JUnit allows you to write code faster while increasing quality JUnit is elegantly simple JUnit tests check their own results and provide immediate feedback JUnit tests can be composed into a hierarchy of test suites Writing JUnit tests is inexpensive JUnit tests increase the stability of software JUnit tests are developer tests JUnit tests are written in Java JUnit is free - 34 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Design of JUnit JUnit is designed around two key design patterns: the Command pattern and the Composite pattern A TestCase is a command object 4Any class that contains test methods should subclass the TestCase class A TestSuite is a composite of other tests, either TestCase instances or other TestSuite instances - 35 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Essential Classes junit.framework.TestCase 4 Allows running multiple tests 4 Does all counting and reporting of errors junit.framework.Assert 4 A set of assert methods 4 Test fails if the assert condition does not hold 4 If a test fails it is counted and reported junit.framework.TestSuite 4 A collection of tests 4 Uses Java introspection to find all the methods start with "test“ and have void parameters. 4 TestSuite's run method executes all the tests - 36 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM JUnit UML Diagram <<Interface>> Test TestResult + run (TestResult) + toString () + countTestCases () : int TestCase # setUp () # tearDown () # runTest () + run (TestResult) - 37 - TestSuite + addTest (Test) + run (TestResult) + addError (TestFailure) +addFailure (TestFailure) + errors () + f ailures () errors f ailures TestFailure + f ailedTest () : Test + thrownException () © Tomás Robles & Joaquín Salvachúa 2005 dit UPM JUnit How to - 38 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM JUnit How to: Outline 1. Write a Test Case 2. Write a Test Suite 3. Run the Tests 4. Organize the Tests - 39 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Step 1: Write a Test Case To write a test case, follow these steps: 1. Define a subclass of TestCase. 2. Override the setUp() method to initialize object(s) under test. 3. Override the tearDown() method to release object(s) under test. 4. Define one or more testXXX() methods that exercise the object(s) under test. 5. Define a suite() factory method that creates a TestSuite containing all the testXXX() methods of the TestCase. 6. Define a main() method that runs the TestCase. - 40 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM A Test Case /** import junit.framework.Test; import junit.framework.TestCase; * Sets up the text fixture. import junit.framework.TestSuite; * * Called before every test case method. public class ShoppingCartTest extends TestCase { */ protected void setUp() { private ShoppingCart _bookCart; _bookCart = new ShoppingCart(); /** Product book = new Product("Extreme Programming", 23.95); * Constructs a ShoppingCartTest * with the specified name. * @param name Test case name. */ _bookCart.addItem(book); } /** public ShoppingCartTest(String name) { super(name); } * Tears down the text fixture. * * Called after every test case method. */ protected void tearDown() { _bookCart = null; } - 41 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM A Test Case (II) /** * Tests the emptying of the cart. */ public void testEmpty() { _bookCart.empty(); assert(_bookCart.isEmpty()); } /** * Tests adding a product to the cart. */ public void testProductAdd() { Product book = new Product ("Refactoring", 53.95); _bookCart.addItem(book); double expectedBalance = 23.95 + book.getPrice(); double currentBalance = _bookCart.getBalance(); double tolerance = 0.0; assertEquals(expectedBalance, currentBalance,tolerance); int expectedItemCount = 2; int currentItemCount = _bookCart.getItemCount(); assertEquals(expectedItemCount, currentItemCount); } - 42 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM A Test Case (III) /** * Tests removing a product from the cart. * * @throws ProductNotFoundException If the * product was not in the cart. */ public void testProductRemove() throws ProductNotFoundException { Product book = new Product("Extreme Programming", 23.95); _bookCart.removeItem(book); double expectedBalance = 23.95 - book.getPrice(); double currentBalance = _bookCart.getBalance(); double tolerance = 0.0; assertEquals (expectedBalance, currentBalance, tolerance); int expectedItemCount = 0; int currentItemCount = _bookCart.getItemCount(); assertEquals(expectedItemCount, currentItemCount); } - 43 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM A Test Case (IV) /** * Tests removing an unknown product from the cart. * * This test is successful if the * ProductNotFoundException is raised. */ public void testProductNotFound() { try { Product book = new Product("Ender's Game", 4.95); _bookCart.removeItem(book); fail("Should raise a ProductNotFoundException"); } catch(ProductNotFoundException pnfe) { // successful test } } - 44 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Step 2: Write a Test Suite To write a test suite, follow these steps: 1. Define a subclass of TestCase. 2. Define a suite() factory method that creates a TestSuite containing all the TestCase instances and TestSuite instances contained in the TestSuite. 3. Define a main() method that runs the TestSuite. - 45 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM A Test Suite /** * Assembles and returns a test suite for * all the test methods of this test case. * * @return A non-null test suite. */ public static TestSuite suite() { // Reflection is used here to add all // the testXXX() methods to the suite. TestSuite suite = new TestSuite(ShoppingCartTest.class); // Alternatively, but prone to error when adding more test case methods... // TestSuite suite = new TestSuite(); // suite.addTest(new ShoppingCartTest("testEmpty")); // suite.addTest(new ShoppingCartTest("testProductAdd")); // suite.addTest(new ShoppingCartTest("testProductRemove")); // suite.addTest(new ShoppingCartTest("testProductNotFound")); // return suite; } - 46 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Test Suite (II) /** * Runs the test case. * * Uncomment either the textual UI, Swing UI, or AWT UI. */ public static void main(String args[]) { String[] testCaseName = {ShoppingCartTest.class.getName()}; //junit.textui.TestRunner.main(testCaseName); //junit.swingui.TestRunner.main(testCaseName); junit.ui.TestRunner.main(testCaseName); } } - 47 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Step 3: Run the Tests Now that we've written a test suite containing a collection of test cases and other test suites, we can run either the test suite or any of its test cases individually Running a TestSuite will automatically run all of its subordinate TestCase instances and TestSuite instances. Running a TestCase will automatically invoke all of its defined testXXX() methods - 48 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Results and JUnit “Failure” != “error” A failure is anticipated and checked for with assertions 4Simplest: Assert.assert(o.func() == 3); 4Signaled with an AssertionFailedError (extends Error) Errors are unanticipated problems 4ArrayIndexOutOfBoundsException - 49 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Test Runners 4 AWT UI Based: • • A handy tool for running test cases Runs test cases and reports failures and errors 4 Swing UI Based • • - 50 - Adds a test dropdown box Keeps a history of tests that have been run © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Step 4: Organize the Tests 1. Create test cases in the same package as the code under test. • For example, the com.mydotcom.ecommerce package would contain all the application-level classes as well as the test cases for those components. If you want to avoid combining application and testing code in your source directories, it's recommended to create a parallel, mirrored directory structure that contains the test code. 2. For each Java package in your application, define a TestSuite class that contains all the tests for verifying the code in the package. - 51 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Step 4: Organize the Tests (II) 3. Define similar TestSuite classes that create higher-level and lower-level test suites in the other packages (and subpackages) of the application. 4. Make sure your build process includes the compilation of all test suites and test cases. • - 52 - This helps to ensure that your tests are always up-to-date with the latest code and keeps the tests fresh. © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Why Use JUnit? Technical considerations 4See previous slide Human considerations 4Testing becomes a creative task 4Testing a programming like activity Management considerations 4The same lenguaje for development and for testing 4Testing is not at the end of the process • Lack of time • Lack of resources - 53 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Who uses JUnit? The programmer for testing their own programs: 4White box testing 4Coverage By also: Independent teams for validating code 4Black box testing Clients and thirds parties 4Acceptance and Conformance Testing - 54 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Recursos http://www.junit.org 4Fuentes de JUnit http://www.infohazard.org/junitee/ http://www.xprogramming.org http://www.junit.org/articles.htm http://www.javaworld.com/javaworld/jw-12-2000/jw-1221junit_p.html http://www.sidewize.com/company/mockobjects.pdf - 55 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM LOG4J - 56 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Depurar / notificar con println public class HelloWorld { public static void main(String[] args) { System.out.println(“Hello world!”); } } - 57 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Complejidad de aplicaciones reales Aplicaciones multihilo y multiusuario. Puede ser un servidor sin “pantalla” y por lo tanto sin posibilidad de imprimir. Distintas instancias de objetos y servicios: mensajes mezclados en pantalla. Utilidad: - 58 - 4Depurar. 4Saber lo que esta pasando 4Control de seguridad: control de ataques/hackers. 4Redireccionable a fichero. © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Hello Log4j import org.apache.log4j.*; public class HelloLog4j { private static Logger logger = Logger.getLogger(HelloLog4j.class); // estático para inicializar. // necesario añadir esta línea en cada clase. public static void main(String[] args) { BasicConfigurator.configure(); // configurar 1 vez en el programa logger.debug(“In the main method"); logger.info("What a beautiful day."); logger.error(“This is an error message.”); } } - 59 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Salida por pantalla 0 [main] DEBUG HelloLog4j - In the main method 0 [main] INFO HelloLog4j - What a beautiful day. 10 [main] ERROR HelloLog4j - This is an error message. - 60 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM org.apache.log4j.Level Orden: DEBUG < INFO < WARN < ERROR < FATAL Otros niveles: 4Level.ALL 4Level.OFF - 61 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Algunos objetos java.util.logging Handlers StreamHandler ConsoleHandler FileHandler SocketHandler MemoryHandler java.util.logging Formatters SimpleFormatter XMLFormatter Posibilidad de configurar con fichero XML. - 62 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM Recursos http://jakarta.apache.org/log4j/ 4Pagina principal de log4j http://jakarta.apache.org/log4j/doc/index.html 4Manual en línea de ANT (normalmente suficiente editar uno existente). http://jakarta.apache.org/log4j/resources.htm l 4Artículos, presentaciones y otros. - 63 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM - 64 - © Tomás Robles & Joaquín Salvachúa 2005 dit UPM