Testing Java Applications using Groovy blocks/en: Unterschied zwischen den Versionen

Aus expecco Wiki (Version 2.x)
Zur Navigation springen Zur Suche springen
K
K (→‎Download: Fix links)
Zeile 223: Zeile 223:
== Download ==
== Download ==


* Eclipse Project with "BankAccount" code - [[Medium:bankaccount-eclipse.zip|bankaccount-eclipse.zip]]
* Eclipse Project with "BankAccount" code - [[Media:bankaccount-eclipse.zip|bankaccount-eclipse.zip]]
* Expecco test suite with tests from this tutorial - [[Medium:bankaccount.ets|bankaccount.ets]]
* Expecco test suite with tests from this tutorial - [[Media:bankaccount.ets|bankaccount.ets]]


== TODO ==
== TODO ==

Version vom 27. Juli 2018, 18:44 Uhr

This example demonstrates how to use the Java Browser, the Java Debugger and the SmallSense plugins for Java application test development. It also gives more examples on how to use Groovy blocks.

The Bank Account Example[Bearbeiten]

Through this tutorial, we'll use a simple "Bank Account" application as system under test. "Bank Account" is a very simple Java library that models banks and accounts and allow transactions among accounts.

The code of the "Bank Account" application is not correct at place by purpose. You may download a full Eclipse project containing the example code at somewhere.

Setting up expecco[Bearbeiten]

For the sake of brevity, in this tutorial we'll use simple local JVM managed by expecco to run "Bank Account"s code. Please read Java Interface Library v2 on how to connect to an already running Java application on a remote machine

As for any Java application, we have to set the classpath properly, so the JVM can find application code.

Let's define an expecco environment variable named CLASSPATH_BANKACCOUNT, defining where the "Bank Account" code is actually located:

Expecco BankAccounts 001.png


Then let's define a "SetUp" block that actually adds the directory to the JVM class path. A simple Smalltalk elementary block will do it:

execute

   JAVA::Java singletonInstance
       addToClassPath: (self environmentAt: 'CLASSPATH_BANKACCOUNT')

This block has to be run before any other Java code using "Bank Account" classes is executed. Putting it as test plan's pre-execution block !ref! might be a good way to ensure it.

Designing a test[Bearbeiten]

Once the class path is set up, we start designing and implementing tests. Let's start with a simple test that creates two bank accounts and then makes a transfer from one account to the other. Then finally the test should check, if the final balances are what we would expect.

The very simple test would be then:

  • create account A1 with initial balance 1000.
  • create account A2 with initial balance 1000.
  • transfer 500 from account A2 to account A1.
  • check that final balance of A1 is 1500
  • check that final balance of A2 is 500.
  • check that no exception was thrown.

We will encapsulate the first three steps into a single special setup block; let's call it Create 2 accounts & make a transaction. it will take the initial balances and the amount to transfer from input pins and report the final balances to output pins. In addition, it will report any possibly raised exception via its exception output pin.

By separating this logic to a separate block we can easily create more tests with different values, to test different scenarios like: to check that an exception is raised when there are not enough funds on a charged account.

So, in expecco, the very simple testcase outlined above would look like:

Expecco BankAccounts 002.png

Implementing the first test[Bearbeiten]

In order to implement the test as outlined above, we implement a block that actually calls the Java API.

Java Browser/en plugin for expecco provides a simple browser to load and browse Java code directly from within the expecco environment. To open a Java Browser on "Bank Account" code, select PluginsJava BrowserOpen... from the expecco main menu and define a new Java browser workspace. A Java browser workspace is a folder where the Java Browser stores all the Java code and sources (similar to an eclipse workspace). You can define multiple workspaces and switch between them at any time. If you don't have a workspace for "Bank Account" yet, just enter an empty directory and new workspace will be created. Initially the workspace is empty, so to actually see the code of "Bank Account", we have add it's code and sources to it. To do so, click on the Open Settings button in the Java Browser window or select WorkspaceSettings from the window menu. In the Settings dialog, click on Add Library and add Bank Account code. Once added and confirmed (by pressing OK button), you may browse through the code, check what classes and methods are available and so on.

Expecco BankAccounts 005.png

Let's implement the Create 2 accounts & make a transaction block now. Create a new Groovy block and write the code that calls the "Bank Account" Java API.

To make writing code a little bit easier, the SmallSense/en plugin together with the Java Browser/en plugin provide limited completion support for Groovy code. The completion engine takes information about available classes and methods from the Java workspace. In other words, if you have no Java browser workspace opened, the completion won't be able to suggest anything useful. Notice, that the completion support is not as advanced as (say) the eclipse engine.

To trigger the completion, press Ctrl-Space:

Expecco BankAccounts 006.png


After some editing, the block's code may look similar to:

import exept.expecco.projects.examples.bankaccount.Bank;
import exept.expecco.projects.examples.bankaccount.Account;
// end of definitions -- do not remove this line unless imports above is empty

def execute() {
    Bank b = new Bank( "Some bank" );

    Account account1 = new Account( "Owner 1" );
    b.addAccount( account1 );
    account1.setBalance( initialBalance1.value() );

    Account account2 = new Account( "Owner 2" );
    b.addAccount( account2 );
    account2.setBalance( initialBalance2.value() );

    try {
        account1.credit(account2, amount.value() );
        exception.value( null );
    } catch ( TransactionException e ) {
        exception.value( e );
    }

    balance1.value( account1.getBalance() );
    balance2.value( account2.getBalance() );
}

Now we have all bits together to implement and run the simple test. It passes.

Expecco BankAccounts 010.png

Debugging tests I[Bearbeiten]

One test passed. but let's create a second one. Similar, but with different, extreme and invalid amount values. Let's try to transfer an awful lot of money so the balance of the credited account would exceed the maximum allowed balance. According to a specification [!ref!] the transaction should not proceed and an TransactionException should be thrown. The test may look as follows:

Expecco BankAccounts 011.png

If you try to run it, you should see it failing. Now it's time to figure out why and this is the point where the Java Debugger/en plugin is useful. Basically, the Java Debugger plugin allows you to debug code running inside the remote JVM - placing breakpoints, single-stepping through the code, inspecting values of variables and objects, etc.

Back to our failing test, the code of the Groovy block is likely to be correct. The actual transfer is done in method BankAccount#credit() [!ref!]. Let's put a breakpoint here and then single-step through the code until we reach the point where the actual computation is done.

To place a breakpoint, open a Java Browser, select class Account and method credit() and then put a breakpoint at the beginning of the method (by double clicking in the editor, left to the line number):

Expecco BankAccounts 012.png

Now run the test again. A Java Debugger window should appear:

Expecco BankAccounts 014.png

The debugger shows the Java execution stack at the top, source code of the selected method in the middle and an inspector for this and for local variables in the bottom part (similar to the builtin expecco debugger for elementary code). Let's single step a little bit further, into the method Transaction#perform() to line 55. Use button Next to step-over to next line and Send to step-into called methods.

You may use the inspector at the bottom to look at the value of amount or other local variables. If you double-click to an object value as, say, source field of the transaction object, a new inspector on that object is opened:

Expecco BankAccounts 015.png

If you like, these little inspector windows can be kept open to see the value as it changes in the future. The code around line 55 in Transaction.java reads as:

54    // Check if destination account would exceed MAX_BALANCE after crediting.
55    if ((oldDestinationBalance + amount) > Account.MAX_BALANCE) {
56            throw new TransactionException("Maximum account balance exceeded +" + source.getId());
57    }
58
59    long newSourceBalance = oldSourceBalance - amount;

It checks if the new balance of the destination account would exceed the maximum, and of so, just throw an exception. At least according to the documentation! By inspecting values of amount and oldDestinationBalance you may see that the values are what one would expect, so if you press Next button, the execution should enter the "if"-body and throw an exception. If you actually do it, you'll see that the condition is satisfied and the execution proceeds to line 59.

This is clearly a bug in the application code (see classical integer overflow in this case). The developer did not care for the possibility of a numeric overflow in the integer code, which wraps around and returns wrong results for values larger the integer range (32bit / 64bit, depending on the integer's type). So the test developer / tester may just submit a bug to development team, and proceed testing further areas of the application.

Debugging tests II[Bearbeiten]

Let's write yet another test that tries to transfer a negative amount. The API documentation does not specify the behaviour in this case explicitly. We might expect the result to look like the in first test, except that the amount being -500 rather than 500 and the final balances being exchanged.

Actually such a test would fail. As you may see, the code throws a ```TransactionException``` with a (rather unspecific) message Internal error occurred during transaction. The message is a bit worrying as, if negative value are not allowed, the error message should say so. Our feeling is that something else went wrong...

Expecco BankAccounts 017.png

To find out, we may again use the Java debugger plugin and place an exception breakpoint, a special kind of breakpoint that stops program execution whenever an exception of a specific type is thrown. To do so, go to PluginsJava DebuggerBreakpoint List. This opens a little window displaying all Java breakpoints, including the line breakpoints we have used earlier. Use the context menu (right-click in the list) to add an exception breakpoint:


Expecco BankAccounts 018.png

A dialog will appear, where you can specify the exception class name. In this case, exept.expecco.projects.examples.bankaccount.TransactionException. Be aware, that it has to be a fully qualified Java class name. Also, you have to tick both Caught and Uncaught checkboxes, as the Java bridge code catches all exceptions.

Expecco BankAccounts 020.png

Now run the test again. A debugger should appear, stopping at line 65 in Transaction.java. The code here simply catches all exceptions and re-throws a TransactionException. So still it's not clear what is the real cause of the exception. To find out, let's check what is the value of the original exception, stored in variable e (click or double-click on the private variable e in the bottom left inspector part of the debugger. That is the list which shows local variables).

It's a java.security.InvalidParameterException. Let's just put another exception breakpoint, now for java.security.InvalidParameterException, and run the test again. Now this should reveal the origin of the problem.

Expecco BankAccounts 021.png

If you run it again, you may see that the exception is thrown in Transaction#check() if the amount specified is less than zero.

Wrap-up[Bearbeiten]

The Java browser plugin, Java Debugger plugin and SmallSense plugin can make test development using Groovy block easier:

  • Java browser plugin provides a way to browse Java code right from the expecco environment, without need of external, third-party IDE.
  • SmallSense plugin provides a simple completion support to Groovy block editor, making editing easier.
  • Java Debugger plugin provides in-expecco debugging facilities to debug Java code running system under test, making test debugging easier.

These plugins are not necessary to use Groovy blocks. However, working with complex Java code might become tricky when it comes to test debugging. While it is possible to use third-party Java IDEs and debuggers, the added value of these plugins is the tight integration with expecco.

For more information, refer to:

Download[Bearbeiten]

TODO[Bearbeiten]

  • cleanup You / we
  • Upload standalone .ets and .zip with Eclipse project Java doc somewhere
  • Upload Java doc somewhere
  • Fix crossrefs (to javadoc and other documents), once above get sorted.



Copyright © 2014-2024 eXept Software AG