Beiträge mit dem Tag ·

Java

·...

Infinite Loop

kein kommentar

Hach, solche Dinge find ich echt schön:

while (true) {
  try {
    return;
  } finally {
    continue;
  }
}

Testing the coverage metric of JMockIt

4 kommentare

After yesterdays article about Code Coverage terminology I thought more about the code coverage metric JMockIt uses. I created a simple class to get more insights:

CoverMeSimple.java

package de.kopis.katas;

public class CoverMeSimple {
    public int simple(int x, int y) {
        int z = x;

        if(y > x)
            z = y;
        z *= 2;

        return z;
    }
}

This is as simple as it gets. The example is taken from the Wikipedia page on Kontrollflussorientierte Testverfahren again. For 100% statement coverage you only need one test case, in which y > x. Then all statements are executed and you have 100% statement coverage. So I wrote this little unit test:

CoverMeSimpleTest.java

package de.kopis.katas;

import static org.junit.Assert.assertEquals;

import mockit.integration.junit4.JMockit;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JMockit.class)
public class CoverMeSimpleTest {
    @Test
    public void testSimple() {
        CoverMeSimple cm = new CoverMeSimple();
        int result = cm.simple(1, 2);
        assertEquals(4, result);
    }
}

And here is the resulting JMockit coverage report:

JMockit Coverage Report of CoverMeSimple

JMockit Coverage Report of CoverMeSimple

JMockit detailed Coverage Report on CoverMeSimple

JMockit detailed Coverage Report on CoverMeSimple

As you can see, JMockit tells us that every single statement is executed, exactly 1 time, with this test case. And that’s exactly what I understand as statement coverage and it is in full compliance to the ISTQB terminology.

Now, to make my point really clear, let me change the class as follows:

package de.kopis.katas;

public class CoverMeSimple {
	public int simple(int x, int y) {
		int z = x;

		if(y > x) {
			z = y;
		} else {

		}

		z *= 2;

		return z;
	}
}

I added the empty ELSE statement that I omitted first. And I run JMockit again to get a new coverage report:

JMockit Coverage report for modified CoverMeSimple

JMockit Coverage report for modified CoverMeSimple


JMockit detailed Coverage report for modified CoverMeSimple

JMockit detailed Coverage report for modified CoverMeSimple

This is not 100% branch coverage, ISTQB certified or not. ;-) My point on this is, if you want to use a tool to verify your testing requirements, make sure that you know what the tool is measuring.

And make sure you read the discussion thread in the JMockit users group.

*Update* I created a Cobertura coverage report for CoverMeSimple now:

CoverMeSimple Cobertura coverage report

CoverMeSimple Cobertura coverage report

Easy code coverage reports with JMockIt

3 kommentare

In this blog post I want to describe how I use JMockIt not only for stubs & mocks, but for easy generation of code coverage reports while developing.

JMockIt is my favorite tool for unit testing, because of it’s ease of use and the many options you get out of this framework. Only recently I decided to try the code coverage report that comes with JMockIt. I was searching for an easy way to monitor my test coverage while continuing development. I didn’t want another tool or another VM running a fancy code review tool. I just wanted to see what my current test cases are covering.
Mehr: Lies den Rest dieses Artikels…

Google Wave Robot in Java

5 kommentare

Heute ging’s mir wieder besser und ich hab mich an meine Google Wave gesetzt. (Noch jemand eine Einladung?) Google Wave ist ein Tool zur Online-Zusammenarbeit, mir kommt es im Moment wie ein Gruppenchat mit erweiterter Textverarbeitung vor. Man kann aber auch Gadgets hinzufügen, also Karten, Buchcover-Anzeigen, Youtube-Videos und anderes. Damit kann man wohl ziemlich viele der in der Zusammenarbeit anfallenden Arbeiten erledigen.

Ich wollte jetzt einen Robot schreiben, quasi ein Programm, das als Benutzer mit in der Wave sitzt und Fragen beantworten kann. Als erstes fiel mir da ein IMDB-Robot ein, der Filmtitel aus dem Text der Wave heraussucht und weitere Details anzeigt. Allerdings scheint die IMDB keine programmatische Abfrage zu unterstützen (und mir ist auch so, als hätte es da vor einigen Wochen Aufregung über die automatische Abfrage gegeben). Glücklicherweise gibt es noch Seiten wie diese, mit der man Abfragen stellen kann. Mein Plan ist also nicht ganz aus der Welt… ;-)

Los ging’s aber erstmal mit einem einfachen Hello World-Robot. Google bietet ein sehr schönes Tutorial zur Wave API. Dort ist auch erklärt, wie man sein Eclipse zum Deployment in die Google AppEngine einrichtet – dort muss der Robot laufen. Die AppEngine ist ein Cloud-Service, in dem eigene Programme laufen können. Der Robot selbst ist quasi ein Servlet, das bestimmte Wave-Event erhält und darauf antwortet.

Nachdem das erste Hallo Welt in meiner Wave aufgetaucht war, habe ich den Robot noch ein wenig verändert. Im Moment antwortet er einfach auf Blips mit dem umgekehrten Text.

package de.kopis.wave.robot;

import java.util.logging.Logger;

import com.google.wave.api.AbstractRobotServlet;
import com.google.wave.api.Blip;
import com.google.wave.api.Event;
import com.google.wave.api.RobotMessageBundle;
import com.google.wave.api.TextView;
import com.google.wave.api.Wavelet;

@SuppressWarnings("serial")
public class WaveRobot1Servlet extends AbstractRobotServlet {
	private static final Logger LOG = Logger.getLogger(WaveRobot1Servlet.class
			.getName());

	@Override
	public void processEvents(final RobotMessageBundle bundle) {
		Wavelet wavelet = bundle.getWavelet();
		LOG.info("Receiving events.");

		if (bundle.wasSelfAdded()) {
			LOG.info("Adding myself to wave.");
			final Blip blip = wavelet.appendBlip();
			reply(blip, "Here I am.");
		}

		for (Event e : bundle.getBlipSubmittedEvents()) {
			LOG.info("A blip was submitted. Reversing it and replying.");
			Blip blip = e.getBlip();
			replyWithReversedText(blip);
		}
	}

	private void replyWithReversedText(final Blip blip) {
		TextView textView = blip.getDocument();
		StringBuffer text = new StringBuffer(textView.getText());
		reply(blip, text.reverse().toString());
	}

	private void reply(final Blip blip, final String text) {
		if (text.length() > 0) {
			Blip newBlip = blip.createChild();
			TextView newTextView = newBlip.getDocument();
			newTextView.append(text);
		}
	}
}

Der Robot hört bisher auf 2 Events, nämlich die Anmeldung neuer Benutzer (WAVELET_PARTICIPANTS_CHANGED) und das Erzeugen eines Blips (BLIP_SUBMITTED). Die beiden Events müssen in der capabilities.xml eingetragen sein:

<?xml version="1.0" encoding="utf-8"?>
<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">
	<w:capabilities>
		<w:capability name="WAVELET_PARTICIPANTS_CHANGED"
			content="true" />
		<w:capability name="BLIP_SUBMITTED" content="true" />
	</w:capabilities>
	<w:version>3</w:version>
</w:robot>

Was mir noch nicht 100%ig klar ist, ist die Versionierung des Robots. Einmal gibt es die Version der AppEngine, dann die Version des Robots. Der Robot muss zwingend neu versioniert werden, wenn sich die Events verändern, auf die er hören soll. Bei der Versionierung der AppEngine geht es wohl eher um Releases, also veränderte Funktionalität. Vielleicht finde ich ja dazu noch ein paar schöne Tutorials oder Erklärungen. Bei meinem Testrobot werde ich wohl nicht weiter versionieren, nur bei Eventänderungen den Zähler hochsetzen.

Ich müsste mal ausprobieren, ob ich den Robot auch in Groovy schreiben kann, denn damit wäre das Verarbeiten von JSON- oder XML-Antworten der Webservices sehr viel einfacher zu schreiben. Es gibt eine Anleitung für AppEngine Groovy, die werde ich mich als nächstes zu Gemüte führen.

Update Noch ein kleiner Nachtrag, nämlich meine web.xml:

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
	<servlet>
		<servlet-name>WaveRobot1</servlet-name>
		<servlet-class>de.kopis.wave.robot.WaveRobot1Servlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>WaveRobot1</servlet-name>
		<url-pattern>/_wave/robot/jsonrpc</url-pattern>
	</servlet-mapping>
</web-app>