Documentation de la version 2.3 (July 9 2007)
© 2001-2007 OFFIS, Tammo Freese.
Traduit originellement de l'anglais par Alexandre de Pellegrin. Maintenue par Henri Tremblay.
EasyMock 2 est une librairie fournissant un moyen simple d'utiliser des Mock Objects pour une interface donnée. EasyMock 2 est disponible sous licence MIT.
Les Mock Objects simulent le comportement du code métier et sont capables de vérifier s'il est utilisé comme prévu. Les classes métier peuvent être testées de façon isolée en simulant leurs objets liés par des Mock Objects.
Ecrire et maintenir des Mock Objects est souvent une tâche pénible et source d'erreurs. EasyMock 2 génère les Mock Objects dynamiquement - pas besoin de les écrire, pas de code généré!
Par défaut, EasyMock supporte la génération de Mock Objects uniquement pour les interfaces. Pour ceux souhaitant générer des Mock Objects pour des classes, il existe une extension disponible sur la page d'accueil d'EasyMock.
easymock2.3.zip
). Il contient le répertoire
easymock2.3
. Ajoutez le jar d'EasyMock (easymock.jar
) de ce répertoire dans votre
classpath.
Pour exécuter les tests d'EasyMock, ajoutez tests.zip
et le jar de JUnit 4.1
à votre classpath and lancez
'java org.easymock.tests.AllTests'
.
Le code source d'EasyMock est situé dans src.zip
.
La plupart des éléments d'un logiciel ne fonctionnent pas de manière isolée mais en collaboration avec d'autres éléments (objets liés) pour effectuer leur tâche. Dans beaucoup de cas, nous ne nous soucions pas d'utiliser des objets liés pour nos tests unitaires du moment que nous avons confiance en eux. Si ce n'est pas le cas, les Mock Objects peuvent nous aider à tester unitairement de façon isolée. Les Mock Objects remplacent les objets liés de l'élément testé.
Les exemples suivants utilisent l'interface Collaborator
:
package org.easymock.samples; public interface Collaborator { void documentAdded(String title); void documentChanged(String title); void documentRemoved(String title); byte voteForRemoval(String title); byte[] voteForRemovals(String[] title); }
Les implémentations de cette interface sont des
objets liés (des listeners dans ce cas) à la classe nommée ClassUnderTest
:
public class ClassUnderTest { // ... public void addListener(Collaborator listener) { // ... } public void addDocument(String title, byte[] document) { // ... } public boolean removeDocument(String title) { // ... } public boolean removeDocuments(String[] titles) { // ... } }
Le code de la classe et de l'interface est disponible dans
le package
org.easymock.samples
dans samples.zip
.
Les exemples qui suivent supposent que vous êtes familier avec le framework de test JUnit. Bien que les tests montrés ici utilisent JUnit version 3.8.1, vous pouvez également utiliser JUnit 4 ou TestNG.
Nous allons maintenant construire un cas de test et jouer avec pour
comprendre les fonctionnalités du package EasyMock. Le
fichier samples.zip
contient une version modifiée de ce test.
Notre premier test devra vérifier que la suppression d'un document non existant ne doit pas
provoquer la notification de l'objet lié. Voici le test dans la définition du Mock Object:
package org.easymock.samples; import junit.framework.TestCase; public class ExampleTest extends TestCase { private ClassUnderTest classUnderTest; private Collaborator mock; protected void setUp() { classUnderTest = new ClassUnderTest(); classUnderTest.addListener(mock); } public void testRemoveNonExistingDocument() { // This call should not lead to any notification // of the Mock Object: classUnderTest.removeDocument("Does not exist"); } }
Pour beaucoup de tests utilisant EasyMock 2, nous avons
uniquement besoin de l'import statique des méthodes de la classe
org.easymock.EasyMock
.
Cette classe est la seule non interne et non dépréciée d'EasyMock 2.
import static org.easymock.EasyMock.*; import junit.framework.TestCase; public class ExampleTest extends TestCase { private ClassUnderTest classUnderTest; private Collaborator mock; }
Pour obtenir un Mock Object, il faut:
Voici le premier exemple:
protected void setUp() { mock = createMock(Collaborator.class); // 1 classUnderTest = new ClassUnderTest(); classUnderTest.addListener(mock); } public void testRemoveNonExistingDocument() { // 2 (we do not expect anything) replay(mock); // 3 classUnderTest.removeDocument("Does not exist"); }
Après activation à l'étape 3, mock
est un Mock Object de l'interface Collaborator
qui n'attend aucun appel. Cela signifie que si nous changeons notre ClassUnderTest
pour appeler n'importe quelle méthode de l'interface, le Mock Object lévera
une AssertionError
:
java.lang.AssertionError: Unexpected method call documentRemoved("Does not exist"): at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29) at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44) at $Proxy0.documentRemoved(Unknown Source) at org.easymock.samples.ClassUnderTest.notifyListenersDocumentRemoved(ClassUnderTest.java:74) at org.easymock.samples.ClassUnderTest.removeDocument(ClassUnderTest.java:33) at org.easymock.samples.ExampleTest.testRemoveNonExistingDocument(ExampleTest.java:24) ...
Écrivons un second test. Si un document est ajouté à
la classe testée, nous nous attendons à un appel à
mock.documentAdded()
sur le Mock Object avec le titre du document en argument:
public void testAddDocument() { mock.documentAdded("New Document"); // 2 replay(mock); // 3 classUnderTest.addDocument("New Document", new byte[0]); }
Aussi, dans l'étape d'enregistrement (avant d'appeler replay
),
le Mock Object ne se comporte pas comme un Mock Object mais enregistre
les appels de méthode. Après l'appel à replay
,
il se comporte comme un Mock Object, vérifiant que les appels
de méthode attendus ont bien lieu.
Si classUnderTest.addDocument("New Document", new byte[0])
appelle la méthode attendue avec un mauvais argument, le
Mock Object lèvera une AssertionError
:
java.lang.AssertionError: Unexpected method call documentAdded("Wrong title"): documentAdded("New Document"): expected: 1, actual: 0 at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29) at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44) at $Proxy0.documentAdded(Unknown Source) at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:61) at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:28) at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30) ...
Tous les appels attendus n'ayant pas eu lieu sont montrés, ainsi que tous les appels faits alors qu'ils étaient non attendus (aucun dans notre cas). Si l'appel à la méthode est effectué trop de fois, le Mock Object le signale également:
java.lang.AssertionError: Unexpected method call documentAdded("New Document"): documentAdded("New Document"): expected: 1, actual: 1 (+1) at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29) at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44) at $Proxy0.documentAdded(Unknown Source) at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:62) at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:29) at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30) ...
Il y a un type d'erreur dont nous ne nous sommes pas
préoccupés jusqu'à présent: si nous décrivons un
comportement, nous voulons vérifier qu'il est bien respecté.
Le test qui suit passe si une méthode du Mock Object est appelée.
Pour vérifier cela, nous devons appeler verify(mock)
:
public void testAddDocument() { mock.documentAdded("New Document"); // 2 replay(mock); // 3 classUnderTest.addDocument("New Document", new byte[0]); verify(mock); }
Si la méthode du Mock Object n'est pas appelée, l'exception suivante sera levée :
java.lang.AssertionError: Expectation failure on verify: documentAdded("New Document"): expected: 1, actual: 0 at org.easymock.internal.MocksControl.verify(MocksControl.java:70) at org.easymock.EasyMock.verify(EasyMock.java:536) at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:31) ...
Le message de l'exception liste tous les appels attendus qui n'ont pas eu lieu.
Jusqu'à maintenant, nos tests ont été faits uniquement
sur un seul appel de méthode. Le test suivant
vérifiera que l'ajout d'un document déjà existant
déclenche l'appel à mock.documentChanged()
avec l'argument approprié. Pour en être certain, nous
vérifions cela trois fois (après tout, c'est un exemple
;-)):
public void testAddAndChangeDocument() { mock.documentAdded("Document"); mock.documentChanged("Document"); mock.documentChanged("Document"); mock.documentChanged("Document"); replay(mock); classUnderTest.addDocument("Document", new byte[0]); classUnderTest.addDocument("Document", new byte[0]); classUnderTest.addDocument("Document", new byte[0]); classUnderTest.addDocument("Document", new byte[0]); verify(mock); }
Afin d'éviter la répétition de mock.documentChanged("Document")
,
EasyMock fournit un raccourci. Nous pouvons spécifier le nombre d'appel avec la méthode
times(int times)
sur l'objet retourné par expectLastCall()
.
Le code ressemble alors à cela:
public void testAddAndChangeDocument() { mock.documentAdded("Document"); mock.documentChanged("Document"); expectLastCall().times(3); replay(mock); classUnderTest.addDocument("Document", new byte[0]); classUnderTest.addDocument("Document", new byte[0]); classUnderTest.addDocument("Document", new byte[0]); classUnderTest.addDocument("Document", new byte[0]); verify(mock); }
Si la méthode est appelée un trop grand nombre de fois, une exception sera levée nous indiquant que la méthode a été appelée trop de fois. L'erreur est levée immédiatement après le premier appel dépassant la limite:
java.lang.AssertionError: Unexpected method call documentChanged("Document"): documentChanged("Document"): expected: 3, actual: 3 (+1) at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29) at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44) at $Proxy0.documentChanged(Unknown Source) at org.easymock.samples.ClassUnderTest.notifyListenersDocumentChanged(ClassUnderTest.java:67) at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:26) at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43) ...
S'il y a trop peu d'appels, verify(mock)
lève une AssertionError
:
java.lang.AssertionError: Expectation failure on verify: documentChanged("Document"): expected: 3, actual: 2 at org.easymock.internal.MocksControl.verify(MocksControl.java:70) at org.easymock.EasyMock.verify(EasyMock.java:536) at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43) ...
Pour spécifier des valeurs de retour, nous encapsulons l'appel attendu dans
expect(T value)
et spécifions la valeur de retour avec la
méthode andReturn(Object returnValue)
sur l'objet retourné par
expect(T value)
.
Prenons par exemple la vérification du workflow lors de la suppresion d'un document.
Si ClassUnderTest
fait un appel pour supprimer un document,
il doit demander aux objets liés de voter pour cette suppression
par appel à byte voteForRemoval(String title)
.
Une réponse positive approuve la suppression. Si la somme de
toutes les réponses est positive, alors le document est
supprimé et l'appel à documentRemoved(String title)
est effectué sur les objets liés:
public void testVoteForRemoval() { mock.documentAdded("Document"); // expect document addition // expect to be asked to vote for document removal, and vote for it expect(mock.voteForRemoval("Document")).andReturn((byte) 42); mock.documentRemoved("Document"); // expect document removal replay(mock); classUnderTest.addDocument("Document", new byte[0]); assertTrue(classUnderTest.removeDocument("Document")); verify(mock); } public void testVoteAgainstRemoval() { mock.documentAdded("Document"); // expect document addition // expect to be asked to vote for document removal, and vote against it expect(mock.voteForRemoval("Document")).andReturn((byte) -42); replay(mock); classUnderTest.addDocument("Document", new byte[0]); assertFalse(classUnderTest.removeDocument("Document")); verify(mock); }
Le type de la valeur de retour est vérifié à la compilation. Par exemple, le code suivant ne compilera pas du fait que le type fourni ne correspond au type retourné par la méthode:
expect(mock.voteForRemoval("Document")).andReturn("wrong type");
Au lieu d'appeler expect(T value)
pour
récuperer l'objet auquel affecter une valeur de retour,
nous pouvons aussi utiliser l'objet retourné par expectLastCall()
.
Ainsi, au lieu de
expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
nous pouvons écrire
mock.voteForRemoval("Document"); expectLastCall().andReturn((byte) 42);
Ce type d'écriture doit uniquement être utilisé si la ligne est trop longue car il n'inclut pas la vérification du type à la compilation.
Afin de spécifier les exceptions (plus précisemment:
les Throwables) devant être levées, l'objet
retourné par expectLastCall()
et expect(T value)
fournit la méthode andThrow(Throwable throwable)
.
Cette méthode doit être appelée durant l'étape
d'enregistrement après l'appel au Mock Object pour lequel le Throwable
doit être levé.
Les exception non "checkées" (comme RuntimeException
,
Error
ainsi que toutes leurs sous classes) peuvent
être levées de n'importe quelle méthode. Les
exceptions "checkées" ne doivent être levées que
pour methodes où cela est prévu.
Parfois, nous voulons que notre Mock Object retourne une valeur ou
lève une exception créée au moment de l'appel.
Depuis la version 2.2 d'EasyMock, l'objet retourné
par expectLastCall()
et expect(T value)
fournit la méthode
andAnswer(IAnswer answer)
permettant de spécifier une implémentation
de l'interface IAnswer
utilisée pour créer
une valeur de retour ou une exception.
Au sein d'IAnswer
, les arguments passés lors de l'appel au mock sont
disponibles via EasyMock.getCurrentArguments()
.
Si vous utilisez cela, les refactorings du type réorganisation
de l'ordre des arguments brisseront vos tests. Vous êtes prévenu.
Il est également possible de spécifier un changement de comportement pour une méthode.
Les méthodes times
, andReturn
et andThrow
peuvent être chaînées. Comme exemple,
nous définissons voteForRemoval("Document")
pour
RuntimeException
sur le quatrième appel,
expect(mock.voteForRemoval("Document")) .andReturn((byte) 42).times(3) .andThrow(new RuntimeException(), 4) .andReturn((byte) -42);
Afin d'être plus permissif sur le nombre d'appels attendus,
des méthodes additionnelles peuvent être
utilisées à la place de times(int count)
:
times(int min, int max)
min
and max
appels,atLeastOnce()
anyTimes()
Si aucun nombre d'appels n'est explicitement défini,
alors seul un appel est attendu. Pour le définir explicitement,
vous pouvez utiliser once()
ou times(1)
.
Sur un Mock Object retourné par EasyMock.createMock()
,
l'ordre d'appel des méthodes n'est pas vérifié.
Si vous souhaitez avoir un Mock Object 'strict' vérifiant cet ordre,
utilisez EasyMock.createStrictMock()
.
Lorsqu'un appel inattendu à une méthode est fait sur
un Mock Object 'strict', le message de l'exception contient les appels
de méthode attendus à ce moment, suivi du premier appel en
conflit. verify(mock)
montre tous les appels de méthode manqués.
Il est parfois nécessaire qu'un Mock Object vérifie
l'ordre d'appel sur certains appels uniquement. Pendant la phase
d'enregistrement, vous pouvez activer la vérification de l'ordre
d'appel en utilisant checkOrder(mock, true)
et la
désactiver en utilisant checkOrder(mock, false)
.
Il y a deux différences entre un Mock Object 'strict' et un Mock Object 'normal':
Pour vérifier la correspondance à un appel de méthode prévu sur un Mock Object,
les arguments de type Object
sont comparés, par défaut, avec
equals()
. Cela peut introduire des problèmes. Considérons l'exemple suivant:
String[] documents = new String[] { "Document 1", "Document 2" }; expect(mock.voteForRemovals(documents)).andReturn(42);
Si la méthode est appelée avec un autre tableau ayant le même contenu,
cela provoque une exception du fait que equals()
compare l'identité
des objets pour les tableaux:
java.lang.AssertionError: Unexpected method call voteForRemovals([Ljava.lang.String;@9a029e): voteForRemovals([Ljava.lang.String;@2db19d): expected: 1, actual: 0 documentRemoved("Document 1"): expected: 1, actual: 0 documentRemoved("Document 2"): expected: 1, actual: 0 at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29) at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44) at $Proxy0.voteForRemovals(Unknown Source) at org.easymock.samples.ClassUnderTest.listenersAllowRemovals(ClassUnderTest.java:88) at org.easymock.samples.ClassUnderTest.removeDocuments(ClassUnderTest.java:48) at org.easymock.samples.ExampleTest.testVoteForRemovals(ExampleTest.java:83) ...
Pour spécifier que seule l'égalité de tableau
est nécessaire pour cet appel, utilisez la méthode
aryEq
, importée statiquement de la classe EasyMock
:
String[] documents = new String[] { "Document 1", "Document 2" }; expect(mock.voteForRemovals(aryEq(documents))).andReturn(42);
Si vous souhaitez utiliser les comparateurs lors d'un appel, vous devez en utiliser pour chaque argument de la méthode appelée.
Voici quelques comparateurs prédéfinis disponible:
eq(X value)
anyBoolean()
, anyByte()
, anyChar()
, anyDouble()
, anyFloat()
, anyInt()
, anyLong()
, anyObject()
, anyShort()
eq(X value, X delta)
float
et double
.aryEq(X value)
Arrays.equals()
. Disponible pour les tableaux d'objets et de types primitifs.isNull()
notNull()
same(X value)
isA(Class clazz)
lt(X value)
, leq(X value)
, geq(X value)
, gt(X value)
Comparable
.startsWith(String prefix), contains(String substring), endsWith(String suffix)
String
s.matches(String regex), find(String regex)
String
s.and(X first, X second)
first
et second
sont vérifiés. Disponible pour tous les types primitifs et objets.or(X first, X second)
first
et second
est vérifié. Disponible pour tous les types primitifs et objets.not(X value)
value
est négatif.cmpEq(X value)
Comparable.compareTo(X o)
. Disponible pour tous les types primitifs numériques et les implémentations de Comparable
.cmp(X value, Comparator<X> comparator, LogicalOperator operator)
comparator.compare(reçue, value) operator 0
où operator
est <,<=,>,>= ou ==.Il peut être intéressant de définir son propre comparateur d'argument. Prenons un comparateur dont le rôle serait de vérifier une exception par rapport à son type et message. Il pourrait être utilisé de la façon suivante:
IllegalStateException e = new IllegalStateException("Operation not allowed.") expect(mock.logThrowable(eqException(e))).andReturn(true);
Deux étapes sont nécessaires pour réaliser cela: le nouveau comparateur
doit être défini et la méthode statique eqException
doit être déclarée.
Pour définir le nouveau comparateur d'argument, nous implémentons l'interface org.easymock.IArgumentMatcher
.
Cette interface contient deux méthodes: matches(Object actual)
, vérifiant
que l'argument reçu est bien celui attendu, et appendTo(StringBuffer buffer)
,
ajoutant au StringBuffer une chaine de caractères représentative du comparateur d'argument.
L'implémentation est la suivante :
import org.easymock.IArgumentMatcher; public class ThrowableEquals implements IArgumentMatcher { private Throwable expected; public ThrowableEquals(Throwable expected) { this.expected = expected; } public boolean matches(Object actual) { if (!(actual instanceof Throwable)) { return false; } String actualMessage = ((Throwable) actual).getMessage(); return expected.getClass().equals(actual.getClass()) && expected.getMessage().equals(actualMessage); } public void appendTo(StringBuffer buffer) { buffer.append("eqException("); buffer.append(expected.getClass().getName()); buffer.append(" with message \""); buffer.append(expected.getMessage()); buffer.append("\"")"); } }
La méthode eqException
doit instancier le
comparateur d'argument avec l'objet Throwable donné, le fournir
à EasyMock via la méthode statique reportMatcher(IArgumentMatcher matcher)
et retourner une valeur afin d'être utilisée au sein de l'appel à la méthode mockée
(typiquement 0
, null
ou false
). Une première tentative ressemblerait à ceci:
public static Throwable eqException(Throwable in) { EasyMock.reportMatcher(new ThrowableEquals(in)); return null; }
Cependant, cela ne fonctionnerait que si la méthode logThrowable
de l'exemple acceptait Throwable
s et quelque chose de plus spécifique du style de RuntimeException
.
Dans ce dernier cas, le code de notre exemple ne compilerait pas:
IllegalStateException e = new IllegalStateException("Operation not allowed.") expect(mock.logThrowable(eqException(e))).andReturn(true);
Java 5.0 à la rescousse: Au lieu de définir eqException
avec un Throwable
en paramètre, nous utilisons un type générique
qui hérite de Throwable
:
public static <T extends Throwable> T eqException(T in) { reportMatcher(new ThrowableEquals(in)); return null; }
Les Mock Objects peuvent être réinitialisés avec reset(mock)
.
Dans certains cas, nous voudrions que nos Mock Object répondent
à certains appels, mais sans tenir compte du nombre de fois, de l'ordre
ni même s'ils ont été eu lieu.
Ce comportement de "stub" peut être défini en utilisant
les méthodes andStubReturn(Object value)
,
andStubThrow(Throwable throwable)
, andStubAnswer(IAnswer<T> answer)
et asStub()
. Le code suivant configure le Mock Object pour répondre 42
à voteForRemoval("Document")
une fois et -1 pour tous les autres arguments:
expect(mock.voteForRemoval("Document")).andReturn(42); expect(mock.voteForRemoval(not(eq("Document")))).andStubReturn(-1);
Pour un Mock Object retourné par createMock()
, le comportement par défaut pour toutes
les méthodes est de léver une AssertionError
pour tous les appels non prévus.
Si vous souhaitez avoir un Mock Object "gentil" autorisant, par défaut, l'appel à
toutes les méthodes et retournant la valeur vide appropriée (0
, null
ou false
), utilisez createNiceMock()
au lieu de createMock()
.
Les comportements des trois méthodes equals()
,
hashCode()
et toString()
ne peuvent être changés sur des Mock Objects créés avec EasyMock,
même si elles font partie de l'interface duquel le Mock Object est créé.
Jusqu'à présent, nous avons vu un Mock Object comme étant
seul et configuré par les méthodes statiques de la classe EasyMock
.
Mais beaucoup de ces méthodes statiques font référence à l'objet "control"
caché de chaque Mock Object et lui délègue l'appel. Un
Mock Control est un objet implementant l'interface IMocksControl
.
Du coup, au lieu de
IMyInterface mock = createStrictMock(IMyInterface.class); replay(mock); verify(mock); reset(mock);
nous pourrions utiliser le code équivalent:
IMocksControl ctrl = createStrictControl(); IMyInterface mock = ctrl.createMock(IMyInterface.class); ctrl.replay(); ctrl.verify(); ctrl.reset();
L'interface IMocksControl
permet de créer plus d'un seul Mock Object.
Ainsi, il est possible de vérifier l'ordre d'appel des méthodes entre les mocks.
Par exemple, configurons deux mock objects pour l'interface IMyInterface
pour lesquels
nous attendons respectivement les appels à mock1.a()
et mock2.a()
,
un nombre indéfini d'appels à mock1.c()
et mock2.c()
,
et enfin mock2.b()
et mock1.b()
, dans cet ordre:
IMocksControl ctrl = createStrictControl(); IMyInterface mock1 = ctrl.createMock(IMyInterface.class); IMyInterface mock2 = ctrl.createMock(IMyInterface.class); mock1.a(); mock2.a(); ctrl.checkOrder(false); mock1.c(); expectLastCall().anyTimes(); mock2.c(); expectLastCall().anyTimes(); ctrl.checkOrder(true); mock2.b(); mock1.b(); ctrl.replay();
Les Mock Objects peuvent ê nommés à leur création en utilisant
createMock(String name, Class<T> toMock)
,
createStrictMock(String name, Class<T> toMock)
ou
createNiceMock(String name, Class<T> toMock)
.
Les noms seront affichés dans le message des AssertionError
.
EasyMock 2 contient une couche de compatibilité. Ainsi, les
tests utilisant EasyMock 1.2 en Java 1.5 fonctionneront sans aucune modification.
Les seules différences connues sont visibles lorsque qu'un test est en erreur: il y a de
légers changements dans les messages d'erreur, les stack traces et les erreurs
sont maintenant remontées en utilisant AssertionError
de Java
au lieu de AssertionFailedError
de JUnit.
EasyMock 2.1 introduisait une fonctionnalité de callback
qui a été retirée dans EasyMock 2.2, car trop complexe.
Depuis EasyMock 2.2, l'interface IAnswer
fournit la fonctionnalité de callback.
EasyMock 1.0 a été développé par Tammo Freese chef OFFIS. Le développement d'EasyMock est hébergé par SourceForge pour permettre à d'autres développeurs et sociétés d'y contribuer.
Rmerciements à ceux qui nous ont fourni retour d'expérience et rustines, incluant Nascif Abousalh-Neto, Dave Astels, Francois Beausoleil, George Dinwiddie, Shane Duan, Wolfgang Frech, Steve Freeman, Oren Gross, John D. Heintz, Dale King, Brian Knorr, Dierk Koenig, Chris Kreussling, Robert Leftwich, Patrick Lightbody, Johannes Link, Rex Madden, David McIntosh, Karsten Menne, Bill Michell, Stephan Mikaty, Ivan Moore, Ilja Preuss, Justin Sampson, Markus Schmidlin, Richard Scott, Joel Shellman, Jiří Mareš, Alexandre de Pellegrin Shaun Smith, Marco Struck, Ralf Stuckert, Victor Szathmary, Henri Tremblay, Bill Uetrecht, Frank Westphal, Chad Woolley, Bernd Worsch, et de nombreux autres.
Merci de consulter la page d'accueil EasyMock pour être informé des nouvelles versions et transmettez vos bogues et suggestions à EasyMock Yahoo!Group (en anglais SVP). Si vous souhaitez souscrire au EasyMock Yahoo!Group, envoyez un message à easymock-subscribe@yahoogroups.com.
EasyMock Version 2.3 (July 9 2007)
Changements depuis la version 2.2:
Changements depuis la version 2.1:
andAnswer(IAnswer answer)
et andStubAnswer(IAnswer answer)
callback(Runnable runnable)
a été retiré, pour un callback, veuillez
convertir à
andAnswer(IAnswer answer)
et andStubAnswer(IAnswer answer)
replay()
, verify()
et reset()
acceptent maintenant
plusieurs mock objects comme arguments
Changements depuis la version 2.0:
EasyMock.getCurrentArguments()
Changements depuis la version 1.2:
java.lang.AssertionError
au lieu
de junit.framework.AssertionFailedError
ce qui permet d'être indépendant
du framework de test. Vous pouvez l'utiliser avec JUnit 3.8.x, JUnit 4 et TestNG