# JUnit - was mocken, was nicht?



## skittish (17. Okt 2009)

Hallo,

stehe gerade vor der stilistischen Frage wie weit ich mit meinen Unit Tests gehen soll. Bisher habe ich den grundsatz der Unabhängigkeit von anderen Objekten mehr oder minder vernachlässigt. Aber manchmal kommt auch folgendes bei rum:


```
@Test
@SuppressWarnings("unchecked")
public void getChildren() {
	// Mocks
	MyField mock = createMock(MyField.class);
	MyField mock_a = createMock(MyField.class);
	MyField mock_b = createMock(MyField.class);
	
	// mock_a & mock_b sind leafs (wird durch isSet() bestimmt)
	expect(mock_a.isSet()).andReturn(false);
	expect(mock_b.isSet()).andReturn(false);
	replay(mock_a);
	replay(mock_b);
	
	// mock soll hingegen kein leaf sein, also sollte dieses MyField einen Iterator liefern
	Iterator<MyField> it = createMock(Iterator.class);
	expect(it.hasNext()).andReturn(true);
	expect(it.next()).andReturn(mock_a);
	expect(it.hasNext()).andReturn(true);
	expect(it.next()).andReturn(mock_b);
	expect(it.hasNext()).andReturn(false);
	replay(it);
	
	expect(mock.isSet()).andReturn(true);
	expect(mock.iterator()).andReturn(it);
	replay(mock);
	
	// noch ein treeNode entstehen lassen
	MyTreeNode node = new MyTreeNode(mock);
	
	// Und testen ob das TreeNode.children funktioniert ...
	Enumeration<MyField> e = node.children();
	assertThat(e, notNullValue());
	assertThat(e.hasMoreElements(), is(true));
	assertThat(e.nextElement(), is(mock_a));
	assertThat(e.hasMoreElements(), is(true));
	assertThat(e.nextElement(), is(mock_b));
}
```

Hier hätte ich einen Unit Test, welcher genau bestimmen kann ob MyTreeNode.children() funktioniert. Und dies unabhängig von der Klasse MyField, welche nichtmals implementiert sein müsste. (Ganz im Sinne des TDD) Es wäre hier weitaus einfacher gewesen die Abhängigkeit von MyField hinzunehmen und auf das Mocken zu verzichten. Mittlerweile halte ich dies für recht zeitaufwändig, zumal man separat nochmal einen Funktionstest durchführen müsste, um Auswirkungen von Änderungen an MyField.isSet() testen zu können.

Kommen wir also zu der entscheidenden Frage: "Wie weit geht Ihr bezüglich Abhängigkeiten in Unit Tests?" Mich interessiert einfach das Vorgehen von anderen, sehe im Bereich Unit Tests sehr wenig fremden Code :/


----------



## maki (17. Okt 2009)

Tests mit Mock Objekten = white box tests = fragile tests
Je mehr die Mocks "wissen", umso fragiler die Tests.

IMHO sieht dein (Test)Code nicht aus als ob er durch TDD erzeugt wurde 

Ansonsten wäre es von Vorteil deine Tests besser zu strukturieren, man erkennt nämlcih nicht auf den ersten Blick worum es geht, dafür aber gibt es Redundanzen(Factory Methoden mit aussagefähigen Namen, eigene Asserts etc. können helfen), die Benamung ist schrecklich(mock_a???), man vergebe mir meine deutlichen Worte 

Ein Buch das ich dir empfehlen kann ist XUnit, hier ein Video zur Einstimmung: YouTube - Automated Testing Patterns and Smells


----------



## skittish (17. Okt 2009)

Vorweg erstmal wie ich es ohne Mocks testen müsste, kurz schluderig konstruiert.

```
@Test
public void getChildren() {
	// Datenstruktur instanzieren
	MyField root = MyFieldFactory.createMyField();
	root.setIdent(6548);
	root.setType(Type.COUNT);
	MyField child1 = MyFieldFactory.createMyField();
	child1.setIdent(4354);
	child1.setType(Type.REAL);
	MyField child2 = MyFieldFactory.createMyField();
	child2.setIdent(435423);
	child2.setType(Type.REAL);
	
	root.addMyField(child1);
	root.addMyField(child2);
		
	// noch ein treeNode entstehen lassen
	MyTreeNode node = new MyTreeNode(root);
	
	// Und testen ob das TreeNode.children funktioniert ...
	Enumeration<MyField> e = node.children();
	assertThat(e, notNullValue());
	assertThat(e.hasMoreElements(), is(true));
	assertThat(e.nextElement(), is(child1));
	assertThat(e.hasMoreElements(), is(true));
	assertThat(e.nextElement(), is(child2));
}
```

Nun habe ich das Problem, dass dieser Test komplett von MyField abhängig ist.
Fehler in MyField führen dazu, dass ein Test, welcher für eine ganz andere Methode geschrieben wurde fehlschlägt. Hätte somit eigentlich schon garkeinen Unit test mehr, sondern eher einen Funktionstest. Oder sind die Begrifflichkeiten nicht so strikt definiert? Bisher ging ich von Unit Tests als testen *einer* Unit aus und nicht des ganzen Konstrukts.

Zum TDD, verstehe ich hier was falsch, wenn ich frage "Wie könnte ich ohne MyField überhaupt testgetrieben entwickeln, wenn nicht mit Hilfe des Mock Objekts?"



Mir ist bewusst, dass der Test nicht schick aussieht, bzw. überhaupt nicht strukturiert ist. Aber es war die einfachste Möglichkeit dies hier in einer Methode zu demonstrieren.
Mock Objekte auslagern würde ich dennoch nur sehr selten, einen Stub schon, aber ein Mock, was einen ganz spezifischen Zweck erfüllt ist zu oft sinnlos. Dies brauche ich in der Form auch nur einmal.


----------



## maki (18. Okt 2009)

Methoden aufzubrechen & Teile auszulagern hat nciht wirklich etwas mit wiederverwendbarkeit zu tun, sondern mit ausdrucksstarkem Code. Allerdings sehe ich Redundanzen in deinem Code, die würden weniger werden.
Jedenfalls ist es nicht unüblich die Erzeugung von Obejkten  (auch von Mocks) auszulagern.

Anstatt Mocks gibt es noch Stubs & Fakes. Ob die besser sind kommt ganz darauf an.

Was genau willst du denn testen?
Die getChildren Methode?
Oder das setzen der Leaf Eigenschaft?


----------

