Seminar Informatik im Rahmen des Master-Studiengangs Technische Informatik Thema: Aufbau, Ziele und Nutzung des Eclipse TPTP Student: Edmond Chouaffé Betreuer: Prof. Dr. Hans W. Nissen Abgabedatum: 02.06.2010 Hiermit versichere ich, dass ich die Seminararbeit selbständig angefertigt und keine anderen als die angegebenen und bei Zitaten kenntlich gemachten Quellen und Hilfsmittel benutzt habe. Edmond Chouaffé
Inhaltverzeichnis Inhaltverzeichnis 1 Introduction... 4 2 Test Driven Development (TDD)... 5 2.1 What is TDD... 5 2.1.1 Add a test... 5 2.1.2 Run all the tests and see if the new one fails... 5 2.1.3 Write some code... 6 2.1.4 Run the tests again and see them succeed... 6 2.1.5 Refactor the code... 6 2.1.6 Repeat... 7 3 Overall objectives of the Eclipse TPTP Project... 8 3.1 Origin of the Eclipse TPTP Project... 8 3.2 Participants in the Eclipse TPTP Project... 8 4 TPTP Project Structure... 9 4.1 The Platform... 9 4.2 The Testing tools... 9 4.2.1 Supported test types... 10 4.2.1.1 JUnit based component testing... 10 4.2.1.2 Manual testing... 11 4.2.1.3 URL testing... 11 4.3 The tracing and profiling tools... 11 4.4 The monitoring tools... 12 5 TPTP project architecture... 13 5.1 TPTP architectural components... 13 5.1.1 Presentation (Controller) system... 13 5.1.2 Target system... 14 5.1.3 The agent controller (AC) [6]... 14 5.1.3.1 Agent controller - Remote scenario... 14 5.1.3.2 Agent controller (Standalone VS Integrated)... 15 6 Profiling and testing a Java application using TPTP... 16 6.1 Installing TPTP... 16 6.2 Profiling a Java application using TPTP... 19 6.2.1 Starting the application in profiling mode... 20 2
Inhaltverzeichnis 6.2.2 Setting the Java program arguments... 21 6.2.3 Setting profiling filters... 21 6.2.4 Profile the Java application... 23 6.2.5 Analyzing the profiled data... 23 6.3 Testing a Java application with the TDD approach using TPTP... 28 6.3.1 Creating a Java class... 28 6.3.2 Setting up TPTP JUnit test suite manually... 28 6.3.2.1 Open the test perspective... 29 6.3.2.2 Create a new TPTP JUnit Test.... 29 6.3.2.3 Add the testrentingonemovie Method.... 30 6.3.2.4 Configure the test execution behavior... 31 6.3.2.5 Enter code for the generated JUnit test method testrentingonemovie... 32 6.3.2.6 Run the test... 33 7 Conclusion... 41 3
1 Introduction 1 Introduction In the current environment of short development cycles for delivering a product, developers tend to focus more on the functional aspects of application execution, mostly via testing, debugging, and code fixing. However, many problems do not easily surface until the application is running in production mode, and gets pushed to limits during some unexpected peak periods. The kinds of performance problems encountered in production cannot be discovered during a debugging session. Before deployed and run in production mode, it is important to use a Profiling tool to analyze application execution and identify performance problems. However before we bother to increase the overall speed of the program or decrease its memory requirement, we must be sure that the application is free of bugs. The occurrence of a bug can have severe consequences. Bugs in critical systems have caused airplane crashes and immense losses to the stock markets. Yet obtaining software without any bugs seems to be an unreachable goal. In fact, the complexity of software is generally intractable, and humans have only limited ability to manage complexity. We are therefore reliant on a system and a technique which will provide us with all the best means possible in order to eliminate the most critical bugs and thus improve quality and reliability. It has been proven that software systems are more reliable if there have been tested throughout their lifecycles which means from the very beginning up to the end. The Eclipse Test and Performance Tools Platform project has exactly been designed to serve this purpose. 4
2 Test Driven Development (TDD) 2 Test Driven Development (TDD) 2.1 What is TDD Test-driven development is a quality-conscious software development technique that relies on the repetition of a very short development cycle: first the developer writes a failing automated test case that defines a desired improvement or new function according to the underlying specifications, then produces code to pass that test and finally refactors the new code to acceptable standards.[2] These tests help the developer write the correct program with regard to the client specifications. The developers must then design automated unit tests that point out the requirements that the code has to meet before writing the code itself. To verify the correctness of the code a test provides assertions that are true in case the code passes the tests or false otherwise. The following steps have been inspired by [2]. 2.1.1 Add a test The idea behind test-driven development is to write the test before the underlying feature. This means that any new feature is motivated by a precise test. The test is so written that it first fails. It must inevitably fail because the needed feature has not been implemented yet. However the developers need to clearly understand the specifications and requirements in order to write the tests which are correct and worthy. 2.1.2 Run all the tests and see if the new one fails This step ensures that the newly added test does in fact fail and not mistakenly pass without requiring any new code. 5
2 Test Driven Development (TDD) Figure 1: Development cycle using the TDD technique [3] 2.1.3 Write some code In this step the functional code is updated for the only purpose of passing the test. The new code may be therefore not perfect and may pass the test in an inelegant way. This should not be a problem anyway at this stage because later steps will improve it. 2.1.4 Run the tests again and see them succeed If all test cases now pass, the programmer can be confident that the code meets all the tested requirements. This is a good point from which to begin the final step of the cycle. 2.1.5 Refactor the code Now the developer can remove any duplication out of the design and clean up the code. By re-running the test cases, the developer can be confident that refactoring is not damaging any existing functionality. Refactoring has significant advantages as improves code readability and reduced complexity to improve the maintainability of the source code, as well as a more expressive internal architecture or object model to improve extensibility.[3] 6
2 Test Driven Development (TDD) 2.1.6 Repeat The next step is to start over with another test, and to repeat the cycle. TDD enables developers to take small steps, typically less than ten new lines. It is far more productive than attempting to code in large steps. In fact, it is much easier to find and fix defects if one has added two new lines than thousand. The TDD technique is gaining more and more popularity among experienced software developers as it requires them to test their code against bugs after every small step which results in a more solid product. 7
3 Overall objectives of the Eclipse TPTP Project 3 Overall objectives of the Eclipse TPTP Project The Eclipse Test and Performance Test Platform is an open source platform which developers can rely on along with its powerful frameworks to build unique test and performance tools for both open source and commercial purposes. The TPTP Project supports the entire test and performance life cycle of an application. This means from the early testing to production including monitoring, test editing and execution, tracing and profiling as well as log analysis capabilities. The support encompasses a wide range of computing systems such as embedded, standalone, enterprise, and high-performance and will continue to expand support to encompass the widest possible range of systems. Besides aiming to reduce the cost and complexity of implementing effective automated software quality (ASQ) control processes, another goal is to have the Eclipse Test and Performance Tools Platform be recognized as a platform of choice for test and performance tools. 3.1 Origin of the Eclipse TPTP Project The TPTP Project is a Top-Level Project in Eclipse Foundation that started in August 2004 as an evolution of the previous Eclipse Hyades project. TPTP subsumes and extends the original Hyades Project that was created in late 2002. [4] 3.2 Participants in the Eclipse TPTP Project The following organizations are currently involved in the development of the project with Intel Corporation as the main participant. Intel IBM Scapa Technologies OC System 8
4 TPTP Project Structure 4 TPTP Project Structure The project consists of four sub projects which are: The platform The testing tools The tracing and profiling tools The monitoring tools. [4] 4.1 The Platform The TPTP Platform Project is the core project and basis for other projects in the Eclipse TPTP Top-Level Project. Basically, the other projects in existence within the TPTP Platform expand and specialise the capabilities and infrastructure which the platform provides by the means of extension points. The platform also offers common user interface, standard data models 1, data collection and communications control, as well as remote execution environments. Data collection from additional environments, operating systems and hardware platforms is being added. [6] 4.2 The Testing tools The Testing Tools addresses the testing phase of the application lifecycle. It open-source, flexible frameworks for building testing tools by extending the TPTP Platform. The framework contains common tools (perspectives, views, editors etc ) for creating, managing and executing tests, deployments, datapools, execution histories and reports. The project also includes exemplary tools for JUnit based component testing tool, Web application performance testing tool, and a manual testing tool. The capability of testing local applications as well as remote ones is hence guaranteed. The project supports the OMG UML2 Test Profile [7]. The UML2 Testing Profile introduces concepts that are necessary for the test specification, such as: 1 The Data Models are abstract descriptions in UML of the types of assets (tests, traces, logs etc.) that the project deals with, and they are provided with a concrete implementation through the Eclipse Modeling Framework (EMF). 9
4 TPTP Project Structure A test suite, which consists of test cases and behaviors, and may be created manually with the test suite editor or automatically by a recorder. A test suite may be associated with a test script (e.g. shell or ANT) or a java class. It can be contained by other test suites (hierarchy). A test log, which contains a collection of test execution traces and results for further analysis. The TPTP provides a viewer to summarize, view, navigate and filter execution events, and associate defects. Test log viewer to summarize, view, navigate and filter execution events, and associated defects Timers, to manipulate and control test behaviour as well as to ensure the termination of test cases. Test cases. Verdicts. A verdict is a predefined enumeration specifying possible test results e.g. pass, inconclusive, fail, and error. Data pools. A data pool provides input and expected output data to a test. It consists of equivalence classes, variables and records. It may be created with the data pool editor or imported from *.CSV files. Behavior. Loops and invocations can be combined to define the behavior of a test to name a few. 4.2.1 Supported test types 4.2.1.1 JUnit based component testing JUnit testing enables the automated unit testing of applications and plug-ins based on JUnit test classes. An editor for creating JUnit and JUnit plug-in test suites and defining metadata, tests and their behaviour is available. It is hence obvious that the TPTP platform is fully compatible with a TDD approach since JUnit has played an important role in development of the TDD. Along with the variety of perspectives and views that the Eclipse Test and Performance Tools Platform supports the developers with, it becomes much easier for them to consider the test as a legitimate part of the development process. JUnit test classes are generated and synchronized automatically from the test suite while preserving user modifications. At this time, only JUnit 3 test cases are handled properly by TPTP [6]. 10
4 TPTP Project Structure 4.2.1.2 Manual testing Manual testing is the testing of applications by human testers based on textual test descriptions (plain text or HTML). The testing tools supply editor for creating manual test suites and defining tests and their behaviour. Provided is also a manual test view for executing a manual test on the target environment by allowing the tester to step through the manual test and capture messages and results, such as: Verdicts. Reasons. Information. Attachments. [6] 4.2.1.3 URL testing URL testing encompasses the automated HTTP performance testing of Web applications from JUnit test classes. The testing tools provide an editor for creating URL test suites and defining tests (HTTP requests) and their behaviour. A URL recorder creates a record of the HTTP requests/responses from user interactions with Web applications to generate performance tests. [6] 4.3 The tracing and profiling tools The Tracing and Profiling Tools addresse the tracing and profiling phases of the application lifecycle. As mentioned in 4.1 the Tracing and Profiling Tools Project provides frameworks for building tracing and profiling tools by extending the TPTP Platform. The framework consists of the Profiling and Logging Perspective and a number of views (e.g. Memory Statistics view, Thread Analysis view, Coverage Statistics view, Object References view, Execution Statistics view to name a few), dialogs and action items that support the capability of collecting and analyzing application performance information as well as memory usage problems. The project includes exemplary profiling tools for various types of applications, including Java and Web applications through monitoring agents that collects trace and profile data. The Profiling Tool offers powerful visualization features that enable you to analyze your application behaviour. 11
4 TPTP Project Structure Memory profiling o Keep track of your objects and find out where the problem spots are. o Find out the origination of your application memory leak. CPU profiling o Find out where your CPU time is going and zero in on performance bottlenecks. Thread profiling o Check the activity of your threads, resolve deadlocks and get detailed information on your application's monitor usage. o Scale your application by evaluating the threading behaviour. The Profiling Tool is presented in more details in the chapter 6.2. 4.4 The monitoring tools The Monitoring Tools Project is intended to be employed during the monitoring and logging phases of the application lifecycle. It expands the TPTP Platform to provide useful frameworks for building monitoring tools. Through its capability of collecting and analyzing application and system resources, the project can be used for monitoring servers and system performance such as CPU and memory utilization [4]. 12
5 TPTP project architecture 5 TPTP project architecture Figure 2: TPTP architecture [6] 5.1 TPTP architectural components 5.1.1 Presentation (Controller) system The controller system contains: 1. The user interface (reference perspectives): the graphical view from which test execution is directed. 2. Data models: based on the Eclipse Modelling Framework (EMF) It includes models for: test execution data logs traces statistics 13
5 TPTP project architecture 3. The Eclipse platform: used for windows, editors, etc. 4. Interfaces to the agent controller, and data collection engine. 5.1.2 Target system The target system includes: 1. the application to be tested 2. the application s execution environment: includes the Java virtual machine and additional monitoring via virtual machine tool interfaces (JVMTI (Java Virtual Machine Tool Interface) for Java 2 SDK version 1.5+, and JVMPI (Java Virtual Machine Profiling Interface) for 1.4.x/1.5.x) 3. the test engine, to start the application and its environment 4. data collection 5.1.3 The agent controller (AC) [6] When profiling an application on a remote machine, or running tests, the standalone agent controller must be installed on this remote machine in order to be able to launch applications remotely (for instance collecting profiling data from a remote web application), and send data back to the local Eclipse TPTP workbench from those remote processes. There exists an implementation of the agent controller for both Linux and Windows platforms. 5.1.3.1 Agent controller - Remote scenario Client: Basically the user running Eclipse. Agent: This is either a profiling agent or a test agent which provides the workbench with data. Agent Controller: The agent controller serves as the communication link between the client and agent. The general theme is: The client notifies the Agent to send or to start collecting data. The agent then returns the data back to the Client (through the agent controller). 14
5 TPTP project architecture There are two important rules to respect when working with the agent controller: 1. Agents will ALWAYS run on the same machine as the agent controller. 2. Only one agent controller may be running on a machine at a time. Additional ACs will fail to start if an existing AC is running. 5.1.3.2 Agent controller (Standalone VS Integrated) The agent controller (AC) has two different forms: The Integrated Agent Controller (IAC): Whenever a TPTPTP functionality is used on your local machine - and from inside Eclipse an integrated agent controller (IAC) is launched automatically. Therefore there is no need to download a separate package for the agent controller. Standalone Agent Controller: The scenario is way different when using TPTP functionality on a remote machine. In fact, it is necessary to download the agent controller as a separate package standalone component from the TPTP workbench components. For a successful remote profiling. it is required that the standalone agent controller must be configured and run before. 15
6 Profiling and testing a Java application using TPTP In this chapter we will demonstrate how to use the TPTP Profiling and Testing tool for analyzing local application behaviour. 6.1 Installing TPTP There are several ways to install the TPTP framework on a machine. Yet we will explain in this chapter how to install the framework from the Galileo update site using the Eclipse update manager. It is recommended to have installed the most recent Eclipse SDK (e.g. 3.5.2) and a relative recent Java Runtime Environment (JRE) or Java Development Kit (JDK) v1.5 or above before. This option is the most convenient and is recommended for people who are new to Eclipse and want the Update Manager to install the files into the correct locations. Another advantage of using this method is the fact that the required dependencies are installed automatically. Follow the instructions bellow to install the TPTP: (See [8]) 1. Start Eclipse. 2. Open Update Manager under Help > Install New Software... Figure 3 Install TPTP 1 16
3. Select Galileo from the Work with drop down list. Figure 4 Install TPTP 2 4. Check Test and Performance and select the Next button to verify the installation details. Figure 5 Install TPTP 3 5. In the Install dialog, select the Next button to start the installation. 17
Figure 6 Install TPTP 4 6. Accept the license agreement(s) and select Finish to start the installation. Figure 7 Install TPTP 5 7. Select Yes when requested to restart Eclipse. Figure 8 Install TPTP 6 8. Verify your installation 18
A quick way to verify your TPTP installation is to make sure a Profile button is available after restart of Eclipse workbench. Figure 9 Install TPTP 7 6.2 Profiling a Java application using TPTP Profiling is the process of generating a statistical analysis of a program that shows processor time and the percentage of program execution time used by each procedure in the program. In this chapter, we will be learning how to use the TPTP Profiling tool to profile a Java application for identifying execution related hot spots. In other words, we learn how to start the profiling session, use the various TPTP views to analyze the data, identify methods with high execution time then jump to the source code to fix the performance problem. As we analyze the data collected, we will use the Profiling and Logging views in the following ways: Identify objects and methods that consume the most time Browse every execution of a method as a function of time Get a wider view of execution behavior as a function of time Identify frequently called methods Study different method invocations The example handled below has been partially inspired by [9] The client registration handled in this article is a relatively simple Java application that inserts client s information into a database table. We won t waste any time on what actually happens to the database. We will rather focus on our Java source code which should be enough to 19
understand this tutorial. You will find a printed version of the source code attached to this file. The main class is ClientRegistration.java. 6.2.1 Starting the application in profiling mode The first step to profiling the product catalog application is to run it in profiling mode. Profile the application by using the Profile As > Java Application popup-menu on the ClientRegistration class as shown in the image below. Figure 10 Running the client in Profiling mode An alternative to starting the application in profiling mode is by using the Profile action available on the Java perspective s toolbar menu. 20
Figure 11 Profile action 6.2.2 Setting the Java program arguments The Profile As > Java Application action will open the configuration and launch wizard as displayed by Fehler! Verweisquelle konnte nicht gefunden werden.. 6.2.3 Setting profiling filters Now it is time to set profiling options to collect method execution information. To set these options, click the Monitor tab as seen in the image below and select a set of profiling options that fits with your performance investigation. Keep in mind that profiling can slow execution significantly, if proper filters are not used. There are commonly three Profiling options available Execution Time Analysis: analyzes the application execution time by monitoring method time information. Memory Analysis: analyzes the application memory usage by monitoring object allocations. Thread Analysis: analyzes the execution of your application threads 1. Select Execution Time Analysis in the Monitor tab to collect execution details 2. Select Edit Options and check Show execution statistics which is directly below Type of data. Click Finish to close the dialog and to save the settings. 21
Figure 12 Execution Time Analysis 1 3. In the Monitor tab, select the Java Profiling item and double click or select Edit Options action. The Filter Set wizard opens. Use the Filter Set page to choose the classes you want to profile. There are a set of predefined filters available but for this sample you will create a new filter set named ClientFilterSet which includes all the java packages. Follow these steps to create the filter set: 3a) Select the Add... action from the filter set list. In the resulting dialog enter ClientFilterSet as the name of the new filter then click OK 3b) Use the Add... button from the Contents of selected filter set list to create the two filters as shown in Figure 1314 and select Finish. 22
Figure 13 Choose classes you want to profile. 6.2.4 Profile the Java application Profile the client registration application by pressing Profile on the Edit Configuration wizard. Choose Yes when asked to switch to the Profiling and Logging perspective. You should see the result of the program execution in the Console view. 6.2.5 Analyzing the profiled data Double click the Execution Time Analysis in the Profiling Monitor perspective to open the Execution Statistics view if it is not already the case. 23
Figure 14 Execution Time Analysis 2 The Execution Statistics view opens by default with the package display mode. 1. There are three display modes available based on the three object types: packages, classes, methods, and instances. To switch between the package, class, method modes, select one of the following toolbar controls: Package Level information Class Level information Method Level information [10] 2. The data displayed can also be shown as percentages. To display the data as percentages, select Show as Percentage in the toolbar. Select the method level information ( ) as we are interested in the execution time of the different methods invoked during execution. Then select Show as Percentage and click once on the column named Cumulative time to sort the methods executed by cumulative time. To get all the methods listed, click on Execution Statistics right at the bottom of the window. The result should be similar to what is presented in the Figure 1516. 24
Figure 15 Execution Statistics view Some of the columns in the above view can be understood as follows: Base Time: For any invocation, the base time is the time taken to execute the invocation, excluding the time spent in other methods that were called during the invocation. Average Base Time: The base time divided by the number of calls. Cumulative Time: For any invocation, the cumulative time is the time taken to execute all methods called from an invocation. If an invocation has no additional method calls, then the cumulative time will be equal to the base time. Calls: The number of calls on the selected method [10]. Surprisingly, the getconnection() method that is implemented in our application has the third highest execution time, and accounts for 25, 55 percent of the application s total execution time. This is an significant hint that we should pay closer attention to that method.. The Execution Statistics have hence helped us identify this method as a potential place to optimize the application's performance. 25
Let s analyse the execution behaviour of the getconnection () method. Open the Method Invocation Details view by double-clicking the getconnection () method within the Execution Statistics view. Figure 16 Method invocation details Figure 1617 presents the execution information for the getconnection () method. As you can see in the selected method invokes table the method invokes 6 different methods. In fact the getconnection() method loads a driver and creates a connection instance in order to be able to connect to tha database. This process may really last for some time and allocates system resources. Additionally, the getconnection() method is invoked 21 times as 21 clients will be inserted at the end of the application execution. The 6 methods called by getconnection() will thus be invoked at least as often as the getconnection() has been invoked. All these calls added together are responsible for the getconnection() method slow execution. Possible Solution to the slow execution. As we can make any changes to the methods outside the scope of our application, the only alternative left that we have is to reduce the number of calls to these methods and consequently to the getconnection () method as well. A proper solution to reach that objective is to create and reuse only one connection instance to insert all the.clients information. To jump to the method source code in order to apply the change, select the method in the Method Invocation Details view then right-click and choose Open Source. Once in the source code, apply the following changes to the getconnection () method. 26
Figure 17: Source code fix The getconnection () method will from now on execute the outer methods only if no connection instance already exists. To validate the performance fix, select the ClientRegistration class in the Java perspective and profile it as learned further above. After the application is executed, open the Execution Statistics View and compare the execution times. Figure 18 Execution Statistic View As you can see in the image above, the getconnection () execution time is now only 8, 12 % of the application execution time. This improvement will prove to be even more valuable as 27
the number clients to be registered increases, so the fix will reduce the application execution time exponential as more clients are being added to the database. Using the Execution Time Analysis to identify and solve performance problem is only one aspect of the TPTP Profiling tool among others which are not covered in this article. 6.3 Testing a Java application with the TDD approach using TPTP Note: Basic understanding of Eclipse and JUnit testing is required to successfully follow this tutorial. In this chapter, you will develop and test a relatively simple Java application using TPTP. The purpose of this tutorial is to illustrate the full support the Eclipse Test and Performance Tools Platform provides for those who want to develop software with respect to the TDD technique. As a result, you will proceed in small steps. The test will then be written first and the code to pass the test afterward. Let s summarize in a few lines the project that is to be developed. Two programmers have got a contract to implement a rental system for DVDs with the following requirements: The charge depends on how long the DVD is rented and as follows: Brand new movies cost 2 Euro for 2 days, and from the third day on, there are additional 1, 75 Euro to be paid per day. Intuitively the Java class gets the name Customer and the corresponding test class CustomerTest. As required by the TDD technique, the test has to be designed in the first place. 6.3.1 Creating a Java class Create a Java project to contain the TPTP JUnit test and the class to be tested. Let s choose Renting for the project name. In the Renting project, create a package named testing. The testing package will be the location of the Java and JUnit classes created in this chapter. 6.3.2 Setting up TPTP JUnit test suite manually. 28
TPTP JUnit Tests should be created manually if they are to exploit the TPTP JUnit Test behavior feature. They can alternatively be imported from existing JUnit tests outside TPTP into a TPTP JUnit Test. All the tests in this chapter will be created manually. 6.3.2.1 Open the test perspective Figure 19: Switch to the Test Perspective 6.3.2.2 Create a new TPTP JUnit Test. In the Test Navigator of the Test Perspective, right-click the Renting project and choose New > Test Element. In the new window, select TPTP JUnit test and click Next. Click Yes to add JUnit libraries if you are asked to do so. In the New TPTP JUnit Test window, type CustomerTest in the Name field. In the Select how the test behavior is edited section, choose the edit in the test editor option (the default). In the Package field browse to select testing as package Click Finish and Yes to open the editor. The TPTP JUnit Test editor appears, showing the CustomerTest test suite. The Overview tab (Figure 2021) includes a test description, Source Information, and a Test Methods listing. Currently, no test methods are defined. For this tutorial, the TPTP JUnit Test editor generates method stubs so the Implement Test Behavior as code option in the Source Information section should be cleared. 29
Figure 20: JUnit Test Suite - Overview Tab If you expand the testing package in the Test Navigator view, you will recognize the newly added java class with the name CustomerTest. Now we can add the first test case to the class. The easiest test case will be to verify the cost for a DVD that is rented for 2 days. We know that this must be 2 Euro. So the code for the test method will be as follows: 6.3.2.3 Add the testrentingonemovie Method. In the Test Methods tab (see Figure 2122), click Add. A default name appears for your test. Add the testrentingonemovie method. In the Name field, type testrentingonemovie for the new test name. Optionally you may enter some text in the description field. 30
Figure 21: JUnit Test Suite - Test Methods tab 6.3.2.4 Configure the test execution behavior. Add a test execution loop. In the Behavior tab (see Figure 2223), click Add... > Loop. In the Name field, type Loop_Customer. In the Number of Iterations field, type 1 (the default value). Add a testrentingonemovie invocation. Select Loop_Customer and click Add... > invocation. The Test Invocation dialog appears. Select testrentingonemovie and click OK. Save the test suite. From the File menu, choose File > Save or click on the disc at the right upper corner of Eclipse as we are used to for common test editors. 31
Figure 22: JUnit Test Suite - Behavior tab Note: the Save command causes the TPTP JUnit Test editor to create test method stubs in CustomerTest.java. 6.3.2.5 Enter code for the generated JUnit test method testrentingonemovie. If you haven t close the CustomerTest test suite then open the Test Methods tab. In the Test Methods tab select testrentingonemovie and then select Open. You are redirected to the CustomerTest.java class. The CustomerTest.java source code appears in the Java editor, including code to setup and execute the test suite, and a method frame for testrentingonemovie. Type the following code within the testrentingonemovie method. Customer customer = new Customer(); customer.rentmovie(1); asserttrue(customer.gettotalcharge() == 2); Because Eclipse is smart enough, it will point out any faulty code as you type. This is normal since you haven t written the code to meet the test requirements yet. Recall that we will be following the TDD approach in this tutorial. Save CustomerTest.java. From the file menu, choose File > Save. 32
6.3.2.6 Run the test In the Test Navigator, right-click the CustomerTest test suite and choose Run As > Test. A Launch Validation Warning popup appears. Click YES to continue launch. Double-click the CustomerTest test log, which appears in the Test Navigator. The CustomerTest test log appears. Select the Events tab to view the test details. By expanding the Events tree, you should see the following events: start of test suite, start of Loop_Customer, test start, test verdict, test stop, loop stop, test suite verdict, and test suite stop. (see Figure 2324) Figure 23: Test log - Events Click on a verdict you are interested in for more details. Alternatively you can use the navigation buttons Figure 24: Navigation buttons to Step through the verdicts 33
to navigate forth and back through the verdicts. In the text section next to the Events tree you will find useful messages and console output from the test execution to fix errors whenever a test fails. You can even step right into the segment of code in the test class which is causing the test to fail if you click on the corresponding error message. These are the possible types of verdicts you can select, depending on the verdicts in the test log: error. fail. inconclusive. pass. all - Navigate through all verdicts [10]. As expected, the test failed since the method rentmovie and gettotalcharge are not implemented yet. The verdict error indicates that there was an error in the code. In the next step we will eliminate the failure by implementing the missing methods. Open the Customer.java class and enter the following code into it: public void rentmovie(int daysrented){ } public int gettotalcharge(){ return 2; } This code certainly looks very simple, but recall that our first goal is to write a code that passes the test. Whether the code does make sense or not is another issue that will be covered as we continue. Save the file and run the test again. If you check out the verdict in the Overview tab of the Test log, you will see that it is now pass. The test for renting one movie has succeeded. We can move on to test the renting for 2 movies. For two movies, the expected charges will be 4 Euro. Open the CustomerTest test suite and switch to the Test Methods tab to add the testrentingtwomovies method. Save the test suite, choose the testrentingtwomovies still in the Test Methods tab. Click Open and enter the following code into the method: 34
Customer customer = new Customer(); customer.rentmovie(1); customer.rentmovie(2); assertequals(4, customer.gettotalcharge()); Save the file. In the behaviour tab of the CustomerTest test suite, focus Loop_Customer and click Add->Invocation to add the testrentingtwomovies method to the loop. Save the test suite and run the test. Open the newly created Test log and switch to the Events tab. The verdict is fail which merely indicates that the test failed. In the Text section, check out the first error message: Junit.framework.AssertionFailedErroe:expected:<4> but was : <2> Open the Customer.java class and write the following lines in the testrentingtwomovies method: private int totalcharge = 0; public void rentmovie(int daysrented){ } totalcharge+=2; public int gettotalcharge(){ return totalcharge; } Run the test and check out the verdict in the Test log. It is pass. We consider now the case a movie is rented for more than three days. As mentioned above, every additional day will cost 1, 75 Euro from the third day on. In the next scenario, a third movie is rented for three days which does 2 Euro + 1, 75 Euro = 3, 75 Euro. The total charge will then be 7, 75 Euro. In addition we accept a tolerance up to 0,001 during comparison. Open the Test Methods tab and add the testrentingthreemovies method. Save the file and then add the method to the Loop_Customer. Open the method and add the following lines into it: Customer customer = new Customer(); customer.rentmovie(1); customer.rentmovie(2); customer.rentmovie(3); assertequals(7.75, customer.gettotalcharge(), 0.001); 35
Run the test and then take a look at the Test log to ensure yourself that it failed. Figure 25 Test log view If you have a look at the Events tree, you will realize that the first two tests passed and only the last one failed. In fact, the expected value is 7, 75 instead of 6 which is currently yielded by the program. Make the following changes to the Customer.java class. private double totalcharge = 0; public void rentmovie(int daysrented) { totalcharge += 2; if (daysrented > 2) totalcharge += 1.75; } public double gettotalcharge() { } return totalcharge; 36
Save the file and run the test. The verdict is still fail. This is due to the change we made to the totalcharge attribute that has moved from int to double. To get rid of the problem, update the testrentingtwomovies as follows: Customer customer = new Customer(); customer.rentmovie(1); customer.rentmovie(2); customer.rentmovie(3); assertequals(7.75, customer.gettotalcharge(), 0.001); The verdict after running the test is now pass. The fourth movie is rented for 4 days which will cost 5, 50. All the charges added together will then make 13, 25. So let s write the test first. Once again, switch to the Test Methods tab to add testrentingfourmovies method. In the Behavior tab, choose the Loop_Customer loop and click add to add the testrentingfourmovies method into the loop. Save the test suite and then open the testrentingfourmovies to add the following lines: Customer customer = new Customer(); customer.rentmovie(1); customer.rentmovie(2); customer.rentmovie(3); customer.rentmovie(4); assertequals(13.25, customer.gettotalcharge(), 0.001); Run the test to see that it expectedly failed. As next, update the Customer.java class and change the rentmovie() method as bellow: public void rentmovie(int daysrented) { totalcharge += 2; if (daysrented > 2) totalcharge += (daysrented - 2)*1.75; } Run the test and check out the verdict. It is pass as we had expected. Our program is so far good enough to go under production as all the tests passed. Nevertheless it doesn t look professional enough. There are definitely a number of points that we could improve to make the code easier to maintain. For instance, we will replace the fixed prices with meaningful names and then declare them as instance variables as below: 37
private double totalcharge = 0; private final double BASE_PRICE= 2.00; private final double PRICE_PER_DAY= 1.75; private final int DAYS_DISCOUNTED= 2; public void rentmovie(int daysrented) { totalcharge += BASE_PRICE; if (daysrented > DAYS_DISCOUNTED) totalcharge += (daysrented - DAYS_DISCOUNTED) * PRICE_PER_DAY; } If you have some doubt, you can still run the test for the verdict. The changes now cause another problem. As a customer can hardly have a base price or days discounted, it seems obvious that we need to create a new class that will better reflect the reality regarding the process of renting movies. Let s then create the class Movie.java which will be responsible for computing the charge in the future. As we are now used to, we first write the test class MovieTest.java to test functional behaviour of the Movie.java class. We use the TPTP to create that class as we learned further above. We use the knowledge we have got so far to add the methods testbaseprice and testpriceperday to the CustomerTest test suite with the following codes: testbaseprice: assertequals(2.00, Movie.getCharge(1),0.001); assertequals(2.00, Movie.getCharge(2),0.001); testpriceperday: assertequals(2.00, Movie.getCharge(3),0.001); assertequals(2.00, Movie.getCharge(4),0.001); Then fill in the Movie.java class with the code below: private static final double BASE_PRICE = 2.00; private static final double PRICE_PER_DAY = 1.75; private static final int DAYS_DISCOUNTED = 2; public static double getcharge(int daysrented) { double result = BASE_PRICE; if (daysrented > DAYS_DISCOUNTED) { 38
} } result += (daysrented - DAYS_DISCOUNTED) * PRICE_PER_DAY; return result; In the Behaviour tab, add the methods testbaseprice and testpriceperday to the Loop_Customer loop. Run the test suite to make sure the code still works. The code for the Customer class now has become a lot smaller: private double totalcharge = 0; public void rentmovie(int daysrented) { } totalcharge += Movie.getCharge(daysRented); public double gettotalcharge() { } return totalcharge; The class CustomerTest class has to be updated in the following way as well: private Customer customer; protected void setup() throws Exception { customer = new Customer(); } public void testrentingonemovie() throws Exception { customer.rentmovie(1); assertequals(2.00, customer.gettotalcharge()); } public void testrentingthreemovies() throws Exception { customer.rentmovie(2); customer.rentmovie(3); customer.rentmovie(4); assertequals(11.25, customer.gettotalcharge(), 0.001); } 39
The methods testrentingtwomovies and testrentingfourmovies have been removed from the Loop_Customer as their duplicate the methods testrentingonemovies and testrentingthreemovies. Save all the changes in order for them to take effect and run the test afterward. Open the Test log for the verdict. The verdict is pass for all the executed test cases. Figure 26 Test log view Our code can now be considered perfect as it passed all the tests it underwent and thus fulfil the requirements as specified above. In this tutorial we learned how to stick to the TDD technique using the TPTP platform. You can now play around with the tools by developing and testing other examples with more confidence. The example we took here just presents a couple a features the TPTP provides. You might play around with the tools to discover more. 40
7 Conclusion 7 Conclusion The examples handled in this article may occur relatively simple. Nevertheless, we could see at certain places how helpful the TPTP platform can be when it comes to considering application performances, quality, managing and designing test cases. This will prove to be even more valuable when projects evolve and that performance and correctness regarding whether or not requirements have been met become real issues. The latest release of TPTP is 4.6.2 and fixes some defects of previous versions. Some of the changes are: The TPTP workbench and Agent Controller configuration no longer supports Java 1.4. The Agent Controller continues to support JVMPI profiling. Test navigating can now be done using short-cuts. For more information, type 'Test Navigating' in the filter text field of the Keys preference page (Window >> Preferences >> General >> Keys). Several usability improvements have been made to the wizards for creating, recording, importing, and exporting test assets. The Test Log Search dialog can now be opened from the context menu in the Events tree. In addition, the Test Log Search dialog can be opened from the Search file menu (Search >> Search... Ctrl+H >> Test Log Search). Large test logs with more than 65,534 events can now be displayed and scrolled in the Events tab of the Test Log editor. The TPTP project is developed by people around the world, from several companies, working fields that all aim for continually integrating even more wizards, views, perspectives to better support application development and this at all stages. 41
Literatures Literatures [1] Testgetriebene Entwicklung mit JUnit & FIT Frank Westphal. Dpunkt.verlag, 1. Auflage 2006 [2] Beck, K. Test-Driven Development by Example, Addison Wesley, 2003 [3] http://en.wikipedia.org/wiki/test-driven_development [4] http://www.eclipse.org/tptp/index.php [5] http://www.eclipse.org/tptp/test/documents/index.php [6] http://www.eclipse.org/tptp/home/documents/conferences/eclipsecon2009/712_profili ngtestingtptp.pdf [7] http://folk.uio.no/oysteinh/conquest-final.pdf. Latest access 27 June 2010 [8] Install TPTP with update manager http://wiki.eclipse.org/install_tptp_with_update_manager [9] Java application profiling using TPTP http://www.eclipse.org/articles/article-tptp-profiling-tool/tptpprofilingarticle.html [10] Help site of the Eclipse IDE 42
Abbildungsverzeichnis Abbildungsverzechnis Figure 1: Development cycle using the TDD technique [3]... 6 Figure 2: TPTP architecture [6]... 13 Figure 3 Install TPTP 1... 16 Figure 4 Install TPTP 2... 17 Figure 5 Install TPTP 3... 17 Figure 6 Install TPTP 4... 18 Figure 7 Install TPTP 5... 18 Figure 8 Install TPTP 6... 18 Figure 9 Install TPTP 7... 19 Figure 10 Running the client in Profiling mode... 20 Figure 11 Profile action... 21 Figure 13 Execution Time Analysis 1... 22 Figure 14 Choose classes you want to profile... 23 Figure 15 Execution Time Analysis 2... 24 Figure 16 Execution Statistics view... 25 Figure 17 Method invocation details... 26 Figure 18: Source code fix... 27 Figure 19 Execution Statistic View... 27 Figure 20: Switch to the Test Perspective... 29 Figure 21: JUnit Test Suite - Overview Tab... 30 Figure 22: JUnit Test Suite - Test Methods tab... 31 Figure 23: JUnit Test Suite - Behavior tab... 32 Figure 24: Test log - Events... 33 Figure 25: Navigation buttons to Step through the verdicts... 33 Figure 26 Test log view... 36 Figure 27 Test log view... 40 43