nfp121, cnam/paris junittests pour...
TRANSCRIPT
NFP1211
NFP121, Cnam/ParisJUnit tests pour Android
Notes sur l’usage de JUnit3 sous Android
Cnam Parisjean-michel Douin, douin au cnam point fr
version en cours
Le lecteur intéressé par un cours sur les tests pourra se référer à celui de l’université de Trente « Software Analysis and Testing » http://selab.fbk.eu/swat/program.ml?lang=en
NFP1212
Avertissement
• Ce support a comme pré-requis :– La connaissance de junit3– Ou la lecture de ce support
• http://jfod.cnam.fr/NFP121/supports/junit3_tests.pd f
NFP1213
Sommaire du « triptyque »
1. Présentation de JUnit, les bases
2. Android et les tests unitaires
3. Assertions et programmation par contrats
NFP1214
Sommaire : Les 3 fichiers
Junit3http://jfod.cnam.fr/NFP121/supports/junit3_tests.pd f
http://jfod.cnam.fr/NFP121/supports/junit3_tests.ja r
Androidhttp://jfod.cnam.fr/NFP121/supports/junit_tests_and roid.pdf
Java et la programmation par contratshttp://jfod.cnam.fr/NFP121/assertions_et_contrats.p df
NFP1215
Sommaire 1)
• Tests et tests unitaires– Outil : junit www.junit.org– Présentation
• Tests d’une application – Architecture MVC : une pile et son IHM
• Tests unitaires de la pile• Tests de plusieurs piles• Tests de l’IHM
– JApplet, JFrame
– Tests en boîte noire– Tests en boîte blanche– Doublures d’objets
• Pertinence des tests– Outil Emma emma.sourceforge.org
NFP1216
Sommaire 2)
• Test unitaires et Android
– Nouvelles Assertions, Nouvelles classes
– Test implicite en boite noire de l’IHM• Tests d’une activity
– Mock Objects
– Tests d’un service
– Tests de la persistance, (d’un « Content Provider »)
NFP1217
Sommaire 3)
– Assertions en Java• Assert, AssertionError• Invariant de représentation, fonction d’abstraction
– Programmation par contrats• Pré-post assertions, invariant de classe• Invariant et variant de boucle, invariant de classe , boucles
– Assertions et héritage• Héritage et pré et post assertions• usage de Jass : source java instrumenté• JML, (JMLUnit), cofoja : usage des annotations
– Initiation à la preuve, • Ce programme respecte les assertions à l’aide d’un démonstrateur• ESC2Java
NFP1218
Bibliographie utilisée
[1] Le cours Software Analysis and Testing de Paolo Tonella , Mariano CeccatoAlessandro Marchetto, Cu Duy Nguyen University of Trento
http://selab.fbk.eu/swat/program.ml?lang=en• Plusieurs figures de ce support sont extraites de cette référence
– http://selab.fbk.eu/swat/slide/3_JUnit.ppt• Lecture préalable indispensable
• http://developer.android.com/resources/tutorials/testing/helloandroid_test.html• http://developer.android.com/guide/topics/testing/index.html• Test Driven Development and Android : http://www.bhecker.com/ap-tdd.ppt
• Emma et Android
– http://stackoverflow.com/questions/2762665/how-to-use-emma-code-coverage-in-android
Le livre utilisé• http://dtmilano.blogspot.com/2008/01/test-driven-development-and-gui-testing.html
Android Application Testing Guide Diego Torres Milano
NFP1219
Rappel : Tests et tests unitaires
• Tests et tests unitaires– Outils : junit3 et junit4
– Le patron Composite• Une feuille est une classe de test• Lecture associée : http://junit.sourceforge.net/doc/cookstour/cookstou r.htm
Objets métiers
Junit ( Low level)junit3 , junit4
NFP12110
Test et Android
• Junit3
• Classes « ordinaires », tests unitaires identiques– assertEquals ….
• Android spécifique:– IHM,– Les services,– La persistance,– Les doublures,– Le « stress » d’une activité.
– Exemple d’une classe proposée par Android :• ActivityInstrumentationTestCase2 extends junit.framework.TestCase
NFP12111
Android L’architecture retenue
• http://developer.android.com/guide/topics/testing/t esting_android.html
NFP12112
IHM : un sommaire
• Une Activity, une IHM
• Accès aux composants graphiques ?
• Accès aux variables d’instance ?
• Comment ?
NFP12113
Applette /Activity, même principe
• A la place d’un utilisateur– Clic, entrée de texte …
• Test avec Android : deux activités– PileActivity– PileActivityTest
NFP12114
Test de l’action empiler
Un scénario de test de l’IHM
1. Écriture d’un nombre2. Cliquer sur le bouton empiler3. Lecture de la zone d’affichage4. Assertions sur le contenu de cette zone
NFP12115
Comment accéder à l’activité à tester ?
• Une classe toute prête:
– ActivityInstrumentationTestCase2<T>• extends junit.framework.TestCase
• Méthodes utiles– getActvity() – getInstrumentation()
– setActivityInitialTouchMode
NFP12116
Le pattern Composite TestCase s’est enrichi
• Extrait de Android Application Testing Guide, Cf. biblio
NFP12117
IntrumentationTestCase
• Extrait de Android Application Testing Guide, Cf. biblio
NFP12118
Test des Activity
• ActivityInstrumentationTestCase2<T>– Prise du contrôle d’une activité
• Marche, arrêt
– Accès aux vues et composants graphiques• Button b = ...
– Génération d’évènements utilisateurs• b.perfomClick();
– Hérite de TestCase• Accès à toute les assertions et bien plus...
• @UiThreadTestpublic void testDeL_IHM() {
NFP12119
Test d’une IHM, des questions se posent
• Accès aux composants graphiques ?– Au sein de l’activité de tests
• Le fichier de ressources de l’activité est accessib le
• Accès aux variables d’instances ?– Par introspection
• Sommes nous toujours en boîte noire …
NFP12120
Rappel : PileActivity, les déclarations
private EditText donnee; private Button boutonEmpiler;private Button boutonDepiler;private EditText sommet;
private TextView contenu ;
Ce sont les attributs de L’IHM
NFP12121
Adéquation Activity/TestActivity
private EditText donnee; private Button boutonEmpiler;private Button boutonDepiler;private EditText sommet;
private PileActivity pileActivity;
private TextView contenu ;
Les attributs de L’IHM deviennent des attributs de l a classe de tests
NFP12122
PileTest … les déclarations
package tp.pile.test;
import tp.pile.PileActivity;import tp.pile.R; // accès aux ressources
public class PileTest extends
ActivityInstrumentationTestCase2<PileActivity> {
public PileTest() {super("pile.tp", PileActivity.class);
}
private PileActivity pileActivity; // L’activité à tester
private EditText donnee; // les composants graphiquesprivate EditText sommet;private TextView contenu;private Button boutonEmpiler;private Button boutonDepiler;
private PileModele<String> pile; // L’instance pile
NFP12123
Affectation des données de l’instance de testsprotected void setUp() throws Exception {
super.setUp();this.pileActivity = this.getActivity();
// par le fichier de ressourcesthis.donnee =
(EditText)pileActivity.findViewById(tp.pile.R.id. donnee);this.sommet =
(EditText)pileActivity.findViewById(tp.pile.R.id. sommet);this.contenu =
(TextView)pileActivity.findViewById(tp.pile.R.id. contenu);this.boutonEmpiler =
(Button)pileActivity.findViewById(tp.pile.R.id. empiler);this.boutonDepiler =
(Button)pileActivity.findViewById(tp.pile.R.id. depiler);
// par introspectionthis.pile = getMember("pileModele", pile, pileActivi ty);
}
NFP12124
Avant le premier test, des pré conditions
• Exécution de la méthode setUp puis
public void testPreconditions() {
assertNotNull(donnee);
assertNotNull(sommet);
assertNotNull(contenu);
assertNotNull(boutonEmpiler);
assertNotNull(boutonDepiler);
assertNotNull(pile);
}
NFP12125
Test action empiler se précise …
Écriture d’un nombreCliquer sur le bouton empiler
Lecture de la zone d’affichageAssertions sur cette zone
donnee.setText(…);boutonEmpiler.performClick();contenu.getText()assertEquals( …)
donneedonneedonneedonneeboutonEmpilerboutonEmpilerboutonEmpilerboutonEmpiler
contenucontenucontenucontenu
NFP12126
Ma première méthode de test
@UiThreadTest
public void testEmpiler() {
donnee.setText("12");
boutonEmpiler.performClick();
donnee.setText("1");
boutonEmpiler.performClick();
String label = contenu.getText().toString();
assertEquals(" Contenu incorrect ???", "[1, 12]",label);
}
NFP12127
Accès aux attributs mêmes privés ?
• Pourquoi faire ?– Sont-ce encore des tests en boites noires ?
• Par introspection
– Field f = obj.getClass().getDeclaredField(name);
– T object = (T)field.get(obj);
NFP12128
Accès aux variables d’instances ?// par introspection, … discussionthis.pile = getMember("pileModele", pile, pileActiv ity);
Avec …@SuppressWarnings("unchecked")public <T> T getMember(String name, T type, Object sourceObj) {
java.lang.reflect.Field field = null;try {
field = sourceObj.getClass().getDeclaredField(name) ;}catch(NoSuchFieldException e) {
fail("L'attribut \"" + memberName + "\" n'existe pas.") ;}field.setAccessible(true);T returnVal = null;
try {returnVal = (T)field.get(sourceObj);
} catch (ClassCastException exc) {fail( name + " n’est pas du bon type.");
} catch (IllegalArgumentException e) {e.printStackTrace();
} catch (IllegalAccessException e) {e.printStackTrace();
}
return returnVal;}
NFP12129
Tests de la variable d’instance …
@UiThreadTest
public void testEmpiler() {
donnee.setText("12");
boutonEmpiler.performClick();
try{
// accès au modèle …
assertEquals ("Le sommet… ???", "12", pile.sommet() );
donnee.setText("1");
boutonEmpiler.performClick();
assertEquals ( "1", pile.sommet() );
}catch(PileVideException e){
fail (" La pile est vide, diantre ! ");
}
}
NFP12130
NFP12131
Architecture des classes possible
• PileActivity ce qui est à tester
• Tests de l’IHM• Tests du modèle• …• Plusieurs paquetages
NFP12132
Architecture : Plusieurs classes
• Plusieurs classes de tests de plusieurs packages– Une seule classe, Cf. TestSuiteBuilder
NFP12133
Résultats junit :
NFP12134
En ligne de commande
• http://developer.android.com/reference/android/test /InstrumentationTestRunner.html
• set path=D:\android-sdk-windows\platform-tools;%PATH%• adb shell am instrument -w cnam.hello.test/android.test.InstrumentationTestRunner•
• cnam.hello.test.HelloAndroidTest:.• Failure in testText:• junit.framework.ComparisonFailure: expected:<... World, HelloActivity!> but was:<..., Android>• at cnam.hello.test.HelloAndroidTest.testText(HelloAndroidTest.java:29)• at java.lang.reflect.Method.invokeNative(Native Method)• at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:204)• at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:194)• at
android.test.ActivityInstrumentationTestCase2.runTest(ActivityInstrumentationTestCase2.java:186)• at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)• at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)• at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:520)• at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447)
• Test results for InstrumentationTestRunner=..F• Time: 0.667
• FAILURES!!!• Tests run: 2, Failures: 1, Errors: 0
NFP12135
En ligne de commande : la pile
• F:\workspace_android_junit_tests\PileTest>adb shell aminstrument -w all.tests/android.test.InstrumentationT estRunner
• tp.pile.test.ihm.PileTestIHM:........• tp.pile.test.persistance.TestPersistance:....• tp.pile.tests.modele.Pile2Test:...............• tp.pile.tests.modele.Pile2_RepOk_AffTest:..• tp.pile.tests.modele.Pile4Test:...............• tp.pile.tests.modele.PileModeleTest:...• Test results for
InstrumentationTestRunner=.......................... ...............• ......• Time: 5.498
• OK (47 tests)
NFP12136
Ligne de commande Android et Emma
• F:\workspace_android_junit_tests\PileTest>adb shell• $ su• su• # export CLASSPATH=/sdcard/emma.jar• export CLASSPATH=/sdcard/emma.jar
• Pas concluant: génération d’un fichier coverage.ecavec 37 octets
NFP12137
Stress
• Random stress testing – From http://d.android.com/guide/developing/tools/mo nkey.html– When the Monkey runs, it generates events and sends them to the
system. It also watches the system under test and looks for three conditions, which it treats specially:
• If you have constrained the Monkey to run in one or more specific packages, it watches for attempts to navigate to an y other packages, and blocks them.
• If your application crashes or receives any sort of unhandled exception, the Monkey will stop and report the erro r.
• If your application generates an application not responding error, the Monkey will stop and report the error.
adb shell monkey -p cnam.hello -v 500
NFP12138
Stress d’une Activity
NFP12139
Emma et Android
• Emma et Android– http://stackoverflow.com/questions/2762665/how-to-use-emma-
code-coverage-in-android
NFP12140
NFP12141
A voir de près
robotiumIt's like Selenium, but for Android™
http://code.google.com/p/robotium/
NFP12142
À terminer
– public class FunctionalTest extends – ActivityInstrumentationTestCase2<AdvancedJokeList> {– public FunctionalTest() { super ("edu.calpoly.android.lab2", AdvancedJokeList.class);}– protected void setUp() throws Exception { super.setUp(); }– public void testAddJoke() {– ArrayList<Joke> m_arrJokeList = null;– m_arrJokeList = this.retrieveHiddenMember ("m_arrJokeList",– m_arrJokeList,getActivity());– assertEquals("Should be 3 default jokes",m_arrJokeList.size(),3);– getActivity().runOnUiThread (new Runnable() {– public void run () {– AdvancedJokeList theActivity = (AdvancedJokeList)getActivity();– EditText et = (EditText)theActivity.– findViewById (edu.calpoly.android.lab2.R.id.newJokeEditText);– Button bt = (Button)theActivity.– findViewById (edu.calpoly.android.lab2.R.id.addJokeButton);– et.setText ("This is a test joke");– bt.performClick ();– }});– getInstrumentation().waitForIdleSync(); // wait for the request to go through– assertEquals("Should be 4 jokes now",m_arrJokeList.size(),4);– assertEquals("Ensure the joke we added is really there",– m_arrJokeList.get(3).getJoke(),"This is a test joke");– }
NFP12143
NFP12144
AndroidTestCase extends junit.framework.TestCase
• Extrait de Android Application Testing Guide, Cf. biblio