Tests unitaires et fonctionnels (UISpec4J library de JUnit)
Je cherche a effectuer des tests unitaires et fonctionnels sur une application java, que je n'ai pas moi meme codee, comprenant des composants Swing. J'ai choisi d'utiliser la "library" UISpec4J qui me paraissait assez bien concue pour cet usage.
Je souhaite verifier que la fentre permettant de se logger reagit bien comme prevu (messages d'erreurs differents en fonction de l'absence du login ou de l'utilisation d'un login n'existant pas)
Apres avoir lu la doc sur le site web d'UISpec4J, j'ai trouve une facon d'intercepter une "window" : http://www.uispec4j.org/interception.html
J'ai donc tente d'utiliser cette fonctionnalite pour capturer la fenetre login de mon application. Pour cela, je lance l'application principale dans la classe UISpecAdapter (http://www.uispec4j.org/apidocs/org/...ecAdapter.html) puis je cree une JWindow grace au Jpanel LoginPanel lance precedemment comme inscrit sur le site de UISpec4J.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class Adapter implements UISpecAdapter {
public org.uispec4j.Window getMainWindow()
{
//lance l'application
lanceWindow();
//recupere le Jpanel puis cree une JWindow
LoginPanel logpanel=LoginPanel.getInstance();
JWindow window = new JWindow();
window.getContentPane().add(logpanel);
//affiche ce JWindow
window.show();
//cree la Window de UISpec4J et y affecte la JWindow
org.uispec4j.Window uispec4jwin = new org.uispec4j.Window(window);
return uispec4jwin;
}
} |
Dans ma fonction test, j'utilise ensuite la fonctionnalite WindowInterceptor et appelle la fonction getMainWindow.
J'essaie ensuite de simuler l'appui de differentes touches puis de tester la validite de mon message.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| public class TestLoginPanel extends UISpecTestCase
{
static
{
UISpec4J.init();
}
static LoginPanel logpanel=LoginPanel.getInstance();
public TestLoginPanel()
{
super(new Adapter());
}
public void testLoginFailed() throws AWTException
{
try {
Window appWindow = WindowInterceptor.run(new Trigger()
{
public void run()
{
getMainWindow();
}
});
//simuler l'appui d'une touche grace a la classe Robot
Robot rob = new Robot();
//login
rob.keyPress(KeyEvent.VK_A);
rob.keyRelease(KeyEvent.VK_A);
rob.keyPress(KeyEvent.VK_B);
rob.keyRelease(KeyEvent.VK_B);
//Tab pour aller jusqu'au champ password
rob.keyPress(KeyEvent.VK_TAB);
rob.keyRelease(KeyEvent.VK_TAB);
//password
rob.keyPress(KeyEvent.VK_A);
rob.keyRelease(KeyEvent.VK_A);
rob.keyPress(KeyEvent.VK_A);
rob.keyRelease(KeyEvent.VK_A);
//tab puis entrer pour valider
rob.keyPress(KeyEvent.VK_TAB);
rob.keyRelease(KeyEvent.VK_TAB);
rob.keyPress(KeyEvent.VK_ENTER);
rob.keyRelease(KeyEvent.VK_ENTER);
//entrer pour fermer le Message d'erreur
rob.keyPress(KeyEvent.VK_ENTER);
rob.keyRelease(KeyEvent.VK_ENTER);
//UISpec4J
JTextComponent jt = new JTextPane();
jt.setText(logpanel.getJOptionPaneInstance().getName());
TextBox box = new TextBox(jt);
box.assertTextEquals("Login Failed");
}
catch (SecurityException e)
{
System.err.println(e.getMessage());
}
}
} |
Lorsque je lance le test, la fenetre JUnit apparait ainsi qu'une version de ma fenetre login denuee de tout caracteres mais fonctionnant nomalement (ce qui est deja bizarre). La simulation de l'appui sur les touches ne fonctionne pas du tout mais je peux moi meme appuyer sur des touches et tester manuellement les differentes possibilites. Une fois que j'ai termine, je ferme la fenetre login et Junit affiche cette erreur: 8O
Code:
1 2 3 4 5 6 7
| junit.framework.AssertionFailedError: No window was shown (timeout expired)
at org.uispec4j.interception.handlers.ShownInterceptionDetectionHandler.waitWindow(ShownInterceptionDetectionHandler.java:31)
at org.uispec4j.interception.WindowInterceptor.run(WindowInterceptor.java:239)
at ui.securityinterface.TestLoginPanel.testLoginFailed(TestLoginPanel.java:252)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) |
Je ne sais pas comment resoudre ce probleme et le code de l'application est difficilement comprehensible. Si quelqu'un a une solution magique a me proposer, j'en serais ravie! Il est tres difficile de trouver de la documentation sur les tests des composants Swing et encore plus sur UISpec4J...
:?
Bien utiliser WindowInterceptor avec UISpec4J
Salut,
Merci de t'intéresser à UISpec4J.
J'ai plusieurs remarques autour de ton test.
D'abord, tu dois choisir clairement si tu veux tester ta boite de dialogue en boite noire (TF) ou en boite blanche (TU).
Dans le premier cas, l'adapter doit contenir un appel au main() de ton appli, puis aucune référence à ton code ne doit apparaitre dans tes tests.
Le rôle de l'Adapter est simplement de récupérer la fenête principale de ton appli (généralement une JFrame).
Un bon exemple d'implémentation d'Adapter serait la suivante:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public class Adapter implements UISpecAdapter {
private Window window;
public Window getMainWindow() {
if (window == null) {
window = WindowInterceptor.run(new Trigger() {
public void run() throws Exception {
Main.main(new String[0]);
}
});
}
return window;
}
} |
Il te faut retenir 3 éléments importants dans cet exemple :
1- la main window est récupérée à à l'aide du WindowInterceptor
2- Le trigger de l'interceptor est exptrêmement simple : il suffit simplement d'apeler ta fonction main()!
3- L'adapter utilise une technique appelée 'lazy evaluation' afin de ne construire l'instance de main window qu'au premier appel à 'getMainWindow()', pour simplement la réutiliser pour les suivants.
Dans le cas où tu fais du Test Unitaire (TU) :
- si ta fenêtre de login est une boite de dialogue (JDialog) tu peux encore te servir de l'Adapter en appelant 'créeLoginJDialog().show()' à la place de 'Main.main()' à l'intérieur de l'interceptor.
- si c'est un JPanel que tu veux tester, crée simplement une instance de org.uispec4j.Panel, construit à partir de ton JPanel, puis joue avec!
Pour jouer avec ton composant, je te suggère l'approche suivante : récupère les éléments importants de ta fenêtre de login (les textfields et les boutons), puis manipule les uniquement à l'aide de l'API de UISpec4J.
Par exemple :
Code:
1 2 3 4 5 6 7 8 9 10
|
public void testLoginFailed() throws Exception {
Window loginDialog = getMainWindow();
loginDialog.getInputTextBox().setText("aWrongLogin");
loginDialog.getPasswordField().setPassword("aa");
WindowInterceptor
.init(loginDialog.getButton("OK").triggerClick())
.processWithButtonClick("Login Failed", "OK");
} |
Ce test très simple va récupérer ton dialogue par l'Adapter (cas de TU). Il effectue ensuite de façon explicite quelques actions utilisateur : nous spécifions ici qu'une mauvaise saisie de login déclenche l'apparition d'un dialogue dont le titre est "Login Failed".
En espérant que cela t'aidera un peu,
Pascal.