Stubs And Moles Dot Net Hub

1 460 vues

Publié le

Publié dans : Technologie, Formation
0 commentaire
0 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

  • Soyez le premier à aimer ceci

Aucun téléchargement
Vues
Nombre de vues
1 460
Sur SlideShare
0
Issues des intégrations
0
Intégrations
30
Actions
Partages
0
Téléchargements
6
Commentaires
0
J’aime
0
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Stubs And Moles Dot Net Hub

  1. 1. Moles, Stubs et PexTest UnitairesIsolés et Paramétrisés<br />Jonathan “Peli” de Halleux<br />Microsoft Research<br />
  2. 2. Objectifs de cette sessionA la fin de cette session, je saurai<br />Ecrire des tests unitaires<br />UtiliserMoles et Stubs pour isoler les tests<br />Ecrire des test unitairesparamétriséavec Pex<br />Ecrire des tests baséssur des transitions d’états<br />
  3. 3. Test Unitaire<br />
  4. 4. A test unitaireest un programmecontenant des assertions qui testeuneunité de code<br />Test Unitaire<br />void PushNonEmpty() {<br />var stack = new Stack();<br />stack.Push(3);<br />Assert.IsFalse(stack.Empty);<br />}<br />
  5. 5. Quiz<br />Les thèmes des questions du quiz…<br />Couverture de code<br />Assertions<br />Isolation<br />La définition de tests unitaires<br />
  6. 6. Le Code à Tester<br />string ReadFooValue() {<br /> string[] lines = File.ReadAllLines(@&quot;t:myapp.ini&quot;);<br />foreach(var line in lines){<br />intindex = line.IndexOf(&apos;=&apos;);<br /> string name = line.Substring(index);<br />if (name == &quot;Foo&quot;) {<br /> string value = line.Substring(index);<br />return value;<br />}<br /> }<br /> return null;<br />}<br />
  7. 7. Quiz: Couverture<br />Combien de couverture de blocs a-t-on besoin?<br />50%<br />80%<br />100%<br />La couverture de blocs n’est pas suffisante<br />
  8. 8. Quiz: Couverture<br />Combien de couverture de blocs a-t-on besoin?<br />50%<br />80%<br />100%<br />La couverture de blocs n’est pas suffisante<br />
  9. 9. Quiz: Couverture<br />Combien de tests pour 100% de couverture de blocs?<br />1<br />2<br />3<br />10<br />1000<br />
  10. 10. Quiz: Couverture<br />Combien de tests pour 100% de couverture de blocs?<br />1<br />2 <br />3<br />10<br />1000<br />
  11. 11. Quiz: Couverture<br />[TestMethod]<br />void ExistingFoo() {<br />File.WriteAllLines(@&quot;t:myapp.ini&quot;,new string[]{“Foo=b”});<br />Reader.ReadFooValue();}<br />Quelautre test pour 100% cov.?<br />
  12. 12. Quiz: Couverture<br />[TestMethod]<br />void ExistingFoo() {<br />File.WriteAllLines(@&quot;t:myapp.ini&quot;,new string[]{“Foo=b”});<br />Reader.ReadFooValue();}<br />Quelautre test pour 100% cov.?<br />[TestMethod]<br />void MissingFoo() {<br />File.WriteAllLines(@&quot;t:myapp.ini&quot;,new string[]{“a=b”});<br />Reader.ReadFooValue();}<br />
  13. 13. Quiz: Assertions<br />Pourquoiécrire des Assertions?<br />Documentation<br />S’assurerque le code est correct<br />Faire plaisir au chef<br />Prévenir de futursfautes<br />Validater des entrées utilisateur<br />Capturer les fautestôtdansl’exécution<br />
  14. 14. Quiz: Assertions<br />Pourquoiécrire des Assertions?<br />Documentation<br />S’assurerque le code est correct<br />Faire plaisir au chef<br />Prévenir de futursfautes<br />Validater des entrées utilisateur<br />Capturer les fautestôtdansl’exécution<br />
  15. 15. Quiz: Assertions<br />if (name == &quot;Foo&quot;) {<br />var value = line.Substring(index);<br />Debug.Assert(???); <br /> return value;<br />}<br />Quelssont de bonsexemplesd’assertions?<br />Debug.Assert(true);<br />Debug.Assert(value != null);<br />Debug.Assert(value.Length == line.Length – (index + 1));<br />No assertions<br />
  16. 16. Quiz: Assertions<br />if (name == &quot;Foo&quot;) {<br />var value = line.Substring(index);<br />Debug.Assert(???); <br /> return value;<br />}<br />Quelssont de bonsexemplesd’assertions?<br />Debug.Assert(true);<br />Debug.Assert(value != null);<br />Debug.Assert(value.Length == line.Length – (index + 1));<br />No assertions<br />
  17. 17. Quiz: Assertions<br />Quelssont de bonsexemplesd’assertions?<br />Assert.IsTrue(value == “b”);<br />Assert.IsTrue(value == null);<br />Assert.IsTrue(String.IsNullOrEmpty(value))<br />Assert.IsTrue(false);<br />No assertions<br />[TestMethod]<br />void MissingFoo() {<br />File.WriteAllLines(@&quot;t:myapp.ini&quot;,new string[]{“a=b”});<br /> string value = Reader.ReadFooValue();<br />Assert.IsTrue(????);}<br />
  18. 18. Quiz: Assertions<br />Quelssont de bonsexemplesd’assertions?<br />Assert.IsTrue(value == “b”);<br />Assert.IsTrue(value == null);<br />Assert.IsTrue(String.IsNullOrEmpty(value))<br />Assert.IsTrue(false);<br />No assertions<br />[TestMethod]<br />void MissingFoo() {<br />File.WriteAllLines(@&quot;t:myapp.ini&quot;,new string[]{“a=b”});<br /> string value = Reader.ReadFooValue();<br />Assert.IsTrue(????);}<br />
  19. 19. Quiz: Couverture +Assertions<br />Comment avoirconfiancedans le code?<br />Haute couverture, peuxd’assertions<br />Bassecouverture, beaucoup d’assertions<br />Haute couverture, peuxd’assertions<br />Bassecouverture, beaucoup d’assertions<br />“Je l’aiécrit”<br />
  20. 20. Quiz: Couverture +Assertions<br />Comment avoirconfiancedans le code?<br />Haute couverture, peuxd’assertions<br />Bassecouverture, beaucoup d’assertions<br />Haute couverture, beaucoup d’assertions<br />Bassecouverture, peuxd’assertions<br />“Je l’aiécrit”<br />
  21. 21. Quiz: Couverture +Assertions<br />Considéronsuneexécution de tests automatisée<br />Comment iplementerune assertion,e.g. Debug.Assert?<br />{ /* ignore */ }<br />Log(c);<br />if(!c) MessageBox.Show(“Assert!”);<br />if(!c) throw new AssertionException();<br />Kill process<br />
  22. 22. Quiz: Couverture +Assertions<br />Considéronsuneexécution de tests automatisée<br />Comment iplementerune assertion,e.g. Debug.Assert?<br />{ /* ignore */ }<br />Log(c);<br />if(!c) MessageBox.Show(“Assert!”);<br />if(!c) throw new AssertionException();<br />Kill process<br />
  23. 23. Quiz: Couverture +Assertions<br />Considéronsuneexécution de tests automatisée<br />Comment iplementerune assertion,e.g. Debug.Assert?<br />{ /* ignore */ }<br />Log(c);<br />if(!c) MessageBox.Show(“Assert!”);<br />if(!c) throw new AssertionException();<br />Kill process<br />1 assertion = <br />1 branch<br />
  24. 24. The Code à Tester<br />string ReadFooValue() {<br /> string[] lines = File.ReadAllLines(@&quot;t:myapp.ini&quot;);<br />foreach(var line in lines){<br />intindex = line.IndexOf(&apos;=&apos;);<br /> string name = line.Substring(index);<br />if (name == &quot;Foo&quot;) {<br /> string value = line.Substring(index);<br />return value;<br />}<br /> }<br /> return null;<br />}<br />
  25. 25. Quiz: Isolation<br />string ReadFooValue() {<br /> string[] lines = File.ReadAllLines(@&quot;t:myapp.ini&quot;);<br /> ...<br />}<br />Quellessont les dépendancesexternes?<br />Réseau<br />Disque local<br />Températureambiante<br />
  26. 26. Quiz: Isolation<br />string ReadFooValue() {<br /> string[] lines = File.ReadAllLines(@&quot;t:myapp.ini&quot;);<br /> ...<br />}<br />Quellessont les dépendancesexternes?<br />Réseau<br />Disquedur<br />Températureambiante<br />
  27. 27. Quiz: Isolation<br />Quelest le problème du disquedur?<br />Le Mappingexiste déjà<br />Les tests ne peuventêtreexécuté en parralèle<br />Le disqueestplein<br />Droitd’accès<br />Pas de problèmes<br />
  28. 28. Quiz: Isolation<br />Quelest le problème du disquedur?<br />Le Mappingexiste déjà<br />Les tests ne peuventêtreexécuté en parralèle<br />Le disqueestplein<br />Droitd’accès<br />Pas de problèmes<br />
  29. 29. Quiz: Isolation<br />Comment gérer le problème?<br />Toujoursexécuterdans le même environment<br />Refactoring: utiliser des Streams<br />Refactoring: introduireIFileSystem<br />Refactoring: passer lines comme argument<br />Change l’implémentation de File.ReadAllLines<br />
  30. 30. Quiz: Isolation<br />Abstractiondevraitêtre la première option<br />Comment gérer le problème?<br />Toujoursexécuterdans le même environment<br />Refactoring: utiliser des Streams<br />Refactoring: introduireIFileSystem<br />Refactoring: passer lines comme argument<br />Change l’implémentation de File.ReadAllLines<br />
  31. 31. Quiz: Isolation<br />Comment gérer le problème?<br />Toujoursexécuterdans le même environment<br />Refactoring: utiliser des Streams<br />Refactoring: introduireIFileSystem<br />Refactoring: passer lines comme argument<br />Change l’implémentation de File.ReadAllLines<br />Dernier ressort<br />
  32. 32. Quiz: Isolation<br />Comment changer File.ReadAllLines?<br />Surcharger la procédure<br />Recompiler le CLR<br />Instrumentation du code<br />Demander poliment<br />
  33. 33. Quiz: Isolation<br />Comment changer File.ReadAllLines?<br />Surcharger la procédure<br />Recompiler le CLR<br />Instrumentation du code<br />Demander poliment<br />
  34. 34. Quiz: Test Unitaire<br />Propriétés de test unitaires?<br />Connection au réseau<br />Exécutelongtemps<br />En mémoire<br />Lit le disquedur<br />Exécuterapidement<br />Reproducible<br />Exécute 10 mèthodes<br />Exécute 100 mèthodes<br />Exécute 10000 mèthodes<br />Requiertune base de données SQL<br />
  35. 35. Quiz: Test Unitaire<br />Propriétés de test unitaires?<br />Connection au réseau<br />Exécutelongtemps<br />En mémoire<br />Lit le disquedur<br />Exécuterapidement<br />Reproducible<br />Exécute 10 mèthodes<br />Exécute 100 mèthodes<br />Exécute 10000 mèthodes<br />Requiertune base de données SQL<br />
  36. 36. Quiz: La Définition d’un Test Unitaire<br />Qu’est-cequ’un Test Unitaire?<br />Un test unitaireest un programme qui exécute (lentement/rapidement) le code à tester, (avec/sans) dépendences à l’environement, (avec/sans) assertions.<br />Qu’est-cequ’unebatterie de tests unitaires?<br />Un ensemble de test unitaires qui atteint un (haut/bas) taux de couverture de code<br />
  37. 37. Quiz: La Définition d’un Test Unitaire<br />Qu’est-cequ’un Test Unitaire?<br />Un test unitaireest un programme qui exécuterapidement le code à tester, sansdépendences à l’environement, avec assertions.<br />Qu’est-cequ’unebatterie de tests unitaires?<br />Un ensemble de test unitaires qui atteint un hauttaux de couverture de code<br />
  38. 38. Isolation avecMoles<br />
  39. 39. Le code à tester ne devrait pas dépendre de l’environement:<br />Comment changerFile.ReadAllLines?<br />Surchargeruneméthodestatique<br />Changer le CLR (et le recompiler)<br />Ecrirel’application en javascript<br />Instrumentation de code<br />Le casse tête du testeur<br />var lines = File.ReadAllLines(@&quot;t:myapp.ini&quot;);<br />
  40. 40. Le code à tester ne devrait pas dépendre de l’environement:<br />Comment changerFile.ReadAllLines?<br />Surchargeruneméthodestatique<br />Changer le CLR (et le recompiler)<br />Ecrirel’application en javascript<br />Instrumentation de code<br />Le casse tête du testeur<br />var lines = File.ReadAllLines(@&quot;t:myapp.ini&quot;);<br />
  41. 41. Et si on savait changer File.ReadAllLinesfacilementdans un contexte de test?<br />Faisons un voeux<br />var lines = File.ReadAllLines(@&quot;t:myapp.ini&quot;);<br />File.ReadAllLines = <br /> delegate(string fileName) {<br /> return new string[]{“a=b”};<br /> }<br />
  42. 42. Avec Moles, on peux le faire:redirigertoutes les futures exécutions de ReadAllLinesvers un délégué qui renvoie{“a=b”}:<br />Molerdes méthodes<br />var lines = File.ReadAllLines(@&quot;t:myapp.ini&quot;);<br />MFile.ReadAllLinesString = <br /> delegate(string fileName) {<br /> return new string[]{“a=b”};<br /> }<br />
  43. 43. Avec Moles, on peux le faire:redirigertoutes les futures exécutions de ReadAllLinesvers un délégué qui renvoie{“a=b”}:<br />Molerdes méthodes<br />var lines = File.ReadAllLines(@&quot;t:myapp.ini&quot;);<br />string[] ReadAllLines(string fileName);<br />MFile.ReadAllLinesString = <br /> delegate(string fileName) {<br /> return new string[]{“a=b”};<br /> }<br />Func&lt;string,string[]&gt; ReadAllLines{ set; }<br />
  44. 44. Quiz: Func&lt;T&gt;<br />Associez les délégués et méthodes<br />Func&lt;string&gt;<br />Action<br />Action&lt;string&gt;<br />Func&lt;bool,string&gt;<br />Func&lt;string, bool&gt;<br />Action&lt;int&gt;<br />Action&lt;List&lt;T&gt;, int&gt;<br />boolFile.Exists(string)<br />Console.WriteLine(string)<br />void Flush()<br />String.Empty {get;}<br />List&lt;T&gt;.Capacity {set;}<br />
  45. 45. Quiz: Func&lt;T&gt;<br />Associez les délégués et méthodes<br />Func&lt;string&gt;<br />Action<br />Action&lt;string&gt;<br />Func&lt;bool,string&gt;<br />Func&lt;string, bool&gt;<br />Action&lt;int&gt;<br />boolFile.Exists(string)<br />Console.WriteLine(string)<br />void Flush()<br />String.Empty {get;}<br />List&lt;T&gt;.Capacity {set;}<br />
  46. 46. C# 3.0 Lambdas<br />MFile.ReadAllLinesString =<br /> delegate(string fileName) {<br /> return new string[]{“a=b”};<br /> }<br />
  47. 47. C# 3.0 Lambdas<br />MFile.ReadAllLinesString = <br />(fileName) =&gt; {<br /> return new string[]{“a=b”};<br /> }<br />
  48. 48. C# 3.0 Lambdas<br />MFile.ReadAllLinesString = <br />(fileName) =&gt;<br /> new string[]{“a=b”};<br />
  49. 49. C# 3.0 Lambdas<br />MFile.ReadAllLinesString = <br />fileName =&gt;<br /> new string[]{“a=b”};<br />
  50. 50. Quiz: Lambdas<br />Associez les lambdas et méthodes<br />() =&gt; “”<br />() =&gt; {}<br />s =&gt; {}<br />(s) =&gt; “”<br />(s) =&gt; false<br />boolFile.Exists(string)<br />Console.WriteLine(string)<br />void Flush();<br />String.Empty {get;}<br />string ToString();<br />
  51. 51. Quiz: Lambdas<br />Associez les lambdas et méthodes<br />() =&gt; “”<br />() =&gt; {}<br />s =&gt; {}<br />(s) =&gt; “”<br />(s) =&gt; false<br />boolFile.Exists(string)<br />Console.WriteLine(string)<br />void Flush();<br />String.Empty {get;}<br />string ToString();<br />
  52. 52. Pour chaqueclasseuneclasse mole<br />Unepropriété par méthode<br />Conventions de noms<br />Structure d’un Mole<br />class File {<br /> static string[] FileReadAllLines(string f);<br />}<br />class MFile {<br />Func&lt;string, string[]&gt; <br />FileReadAllLinesString { set; }<br />}<br />
  53. 53. Quiz: Moles<br />Convention de noms:<br />‘M’ + nom de classe<br />Nom de méthode+ noms des classes des paramètres<br />Accesseur de propriétés: Get<br />Quelest le mole de boolFile.Exists(string)?<br />SFile.ExistsString<br />MFile.Exists<br />MFile.ExistsStringBool<br />MFile.ExistsString<br />
  54. 54. Quiz: Moles<br />Convention de noms:<br />‘M’ + nom de classe<br />Nom de méthode+ noms des classes des paramètres<br />Accesseur de propriétés: Get<br />Quelest le mole de boolFile.Exists(string)?<br />SFile.ExistsString<br />MFile.Exists<br />MFile.ExistsStringBool<br />MFile.ExistsString<br />
  55. 55. Injection de détoursdans le corps des méthodes avec un profiler<br />DétoursCourt circuit de méthodes<br />
  56. 56. Injection de détoursdans le corps des méthodes avec un profiler<br />DétoursCourt circuit de méthodes<br />structDateTime{<br /> static DateTime Now {<br /> return InternalNow();<br /> }<br />}<br />
  57. 57. Injection de détoursdans le corps des méthodes avec un profiler<br />DétoursCourt circuit de méthodes<br />structDateTime{<br /> static DateTime Now {<br /> return InternalNow();<br /> }<br />}<br />Func&lt;DateTime&gt; f = GetDetour(...);<br /> if(f != null) return f();<br />
  58. 58. Demo<br />
  59. 59. Molesen action<br />“Remplacerquelconqueméthode .NET avec un délégué”<br />L’instrumentationrequiertune configuration spéciale:<br />[HostType(“Moles”)] avec MSTest<br />MFile.ReadAllLinesString= (f) =&gt; new string[0];<br />
  60. 60. Jusqu’ici on a appris<br />La définition de tests unitaires<br />L’isolation de tests unitaires avec Moles<br />Identifier les dépendencesexternes<br />Replacer chaque API externe avec un délégué<br />
  61. 61. Pause<br />10 Minutes<br />
  62. 62. Isolation avecStubs<br />
  63. 63. The Code à Tester<br />string ReadFooValue() {<br /> string[] lines = File.ReadAllLines(@&quot;t:myapp.ini&quot;);<br />foreach(var line in lines){<br />intindex = line.IndexOf(&apos;=&apos;);<br /> string name = line.Substring(index);<br />if (name == &quot;Foo&quot;) {<br /> string value = line.Substring(index);<br />return value;<br />}<br /> }<br /> return null;<br />}<br />
  64. 64. Dependency Injection<br />interface IFileSystem {<br /> string[] ReadAllLines(string fileName);}<br />string ReadFooValue(IFileSystemfs) {<br /> string[] lines = fs.ReadAllLines(@&quot;t:myapp.ini&quot;);<br /> ...<br />}<br />
  65. 65. Structure d’un Stub<br />interface IFileSystem {<br /> string[] ReadAllLines(string fileName);}<br />class SIFileSystem : IFileSystem, IStub {<br /> public Func&lt;string,string[]&gt; ReadAllLinesString;<br /> string[] IFileSystem.ReadAllLines(string name){<br /> return this.ReadAllLinesString(name);<br /> } }<br />
  66. 66. Stub en action<br />class SIFileSystem : IFileSystem, IStub {<br /> public Func&lt;string,string[]&gt; ReadAllLinesString;<br /> string[] IFileSystem.ReadAllLines(string name){<br /> return this.ReadAllLinesString(name);<br /> } }<br />var lines = { “foo=a”, “b=c”};<br />varfs = new SIFileSystem{ReadAllLinesString = f =&gt; lines<br />};<br />ReadFooValue(fs);<br />
  67. 67. Jusqu’ici on a appris<br />La définition de tests unitaires<br />L’isolation de tests unitaires avec Moles<br />L’isolation de tests unitaires avec Stubs<br />
  68. 68. Stubs vsMoles<br />Moles pour le code des autres<br />“pas le choix”<br />Stubs pour votre code<br />Refactoring + interfaces + Stubs<br />
  69. 69. Test UnitaireParamétrisé<br />
  70. 70. The recette d’un Test Unitaire<br />3 ingrédientsétentiels:<br />Données<br />Séquence de méthodes<br />Assertions<br />void PushIsNotEmpty() {<br />int item = 3;<br />var stack = new Stack();<br />stack.Push(item); <br />Assert.IsTrue(stack.IsEmpty);<br />}<br />
  71. 71. Quiz: stack.Push (???)<br />stack.Push(???);<br />Quelledonnéeutiliser?<br />0<br />1<br />int.MaxValue, int.MinValue<br />-1<br />1000<br />Peuimporte<br />Il faux d’abord lire le code<br />
  72. 72. Quiz: stack.Push (???)<br />stack.Push(???);<br />Quelledonnéeutiliser?<br />0<br />1<br />int.MaxValue, int.MinValue<br />-1<br />1000<br />Peuimporte<br />Il faux d’abord lire le code<br />
  73. 73. Test UnitaireParamétrisé = <br /> Test Unitaire avec Parametres<br />Separation de concepts<br />Spécification<br />Données pour avoir de la couverture de code<br />Test UnitaireParamétrisé<br />void PushIsNotEmpty(Stack stack, int item) {<br />stack.Push(item);<br />Assert.IsFalse(stack.IsEmpty);<br />}<br />
  74. 74. Test UnitaireParamétrisé<br />void PushIsNotEmpty(Stack stack, int item) {<br />stack.Push(item);<br />Assert.IsFalse(stack.IsEmpty);<br />}<br />Test UnitaireParamétrisé = <br /> Test Unitaire avec Parametres<br />Separation de concepts<br />Spécification<br />Données pour avoir de la couverture de code<br />pour tout stack,<br />pour tout item,<br />… ajouter un element et le stack n’est pas vide<br />
  75. 75. Génération de donnéesavec l’exécutiondynamiquesymbolique<br />
  76. 76. Goal: Soit un programmeparamétrisé, générerautomaticement un ensemble de donnéesqui, à l’exécution, vontatteindre un maximum de cheminsd’exécution<br />Quelle technique pourrait-on utiliser?<br />76<br />Le challengede la génération de données<br />
  77. 77. ExécutiondynamiquesymboliqueExample<br />Choiser le prochain chemin<br />Exécuter&Observer<br />Résoudre<br />void CoverMe(int[] a)<br />{<br /> if (a == null) return;<br /> if (a.Length &gt; 0)<br /> if (a[0] == 1234567890)<br />throw new Exception(&quot;bug&quot;);<br />}<br />Observed constraints<br />a==null<br />a!=null &&<br />!(a.Length&gt;0)<br />a!=null &&<br />a.Length&gt;0 &&<br />a[0]!=1234567890<br />a!=null &&<br />a.Length&gt;0 &&<br />a[0]==1234567890<br />Data<br />null<br />{}<br />{0}<br />{123…}<br />Constraints to solve<br />a!=null<br />a!=null &&<br />a.Length&gt;0<br />a!=null &&<br />a.Length&gt;0 &&<br />a[0]==1234567890<br />a==null<br />F<br />T<br />a.Length&gt;0<br />T<br />F<br />Done: There is no path left.<br />a[0]==123…<br />T<br />F<br />
  78. 78. ExécutiondynamiquesymboliqueExample<br />Choose next path<br />Quelstests Pex générera-t-il?<br />Execute&Monitor<br />Solve<br />void CoverMe2(<br />int[] a, int index) <br />{<br /> if (a[index] == <br /> 1 + a[index + 1]) <br />throw new Exception(&quot;bug&quot;);<br />}<br />Observed constraints<br />Data<br />Constraints to solve<br />F<br />T<br />T<br />F<br />T<br />F<br />
  79. 79. Quiz: Exécutiondynamiquesymbolique<br />Quels tests Pex générera-t-il?<br />(null, 0), ({0,1}, 0)<br />(null, 0), ({0,1}, 0), ({0,1}, 1)<br />({}, 1), ({0,0,0,0}, 3)<br />(null, 0), ({}, 0), ({0}, 0), ({0}, 1), ({1}, 0), ({0,0},0), ({0,1}, 0)<br />void CoverMe2(int[] a, int index) {<br /> if (a[index] == 1 + a[index + 1]) <br /> throw new Exception(&quot;bug&quot;);<br />}<br />
  80. 80. Demo<br />
  81. 81. Jusqu’ici on a appris<br />La définition de tests unitaires<br />L’isolation de tests unitaires avec Moles<br />L’isolation de tests unitaires avec Stubs<br />Test unitairesparamétrisés avec Pex<br />
  82. 82. Behaved TypesTests à base de transition d’état<br />
  83. 83. Behaved file system<br />interface IFileSystem {<br /> string[] ReadAllLines(string fileName);}<br />class BIFileSystem : SIFileSystem {<br />BehavedDictionary&lt;string, string[]&gt; files; <br /> public BIFileSystem() {<br />this.files= <br /> new BehavedDictionary&lt;string, string[]&gt;(this,”Files”);<br />this.ReadAllLinesString= fn =&gt; {<br /> string[] lines;<br /> if (!this.files.TryGetValue(fn, out lines))<br /> throw new FileNotFoundException(fn);<br /> return (string[])lines.Clone();<br /> };<br /> }<br />}<br />
  84. 84. Behaved file system<br />interface IFileSystem {<br /> string[] ReadAllLines(string fileName);}<br />On approxime le systême de fichiers par un dictionnaire fileName->lignes<br /> <br />
  85. 85. Behaved file system<br />interface IFileSystem {<br /> string[] ReadAllLines(string fileName);}<br />class BIFileSystem : SIFileSystem {<br />BehavedDictionary&lt;string, string[]&gt; files; <br /> public BIFileSystem() {<br />this.files= <br /> new BehavedDictionary&lt;string, string[]&gt;(this,”Files”);<br />this.ReadAllLinesString= fn =&gt; {<br /> string[] lines;<br /> if (!this.files.TryGetValue(fn, out lines))<br /> throw new FileNotFoundException(fn);<br /> return (string[])lines.Clone();<br /> };<br /> }<br />}<br />Undefined state<br />
  86. 86. Démo<br />
  87. 87. What you learnedso far<br />The Definition of Test Unitaire<br />Unit Test Isolation through Moles<br />Unit Tests Isolation through Stubs<br />Stated-based Unit Tests with Behaved Types <br />
  88. 88. Break<br />2 Minutes<br />
  89. 89. Jusqu’ici on a appris<br />La définition de tests unitaires<br />L’isolation de tests unitaires avec Moles<br />L’isolation de tests unitaires avec Stubs<br />Test unitairesparamétrisés avec Pex<br />Test à base de transition d’état avec Behaved Types<br />
  90. 90. Patterns<br />
  91. 91. PatternNormalized Roundtrip<br />For an API f(x), f-1(f(f-1(x)) = f-1(x) for all x<br />void ParseToString(string x) {<br />varnormalized = int.Parse(x); <br />var intermediate = normalized.ToString(); <br />varroundtripped = int.Parse(intermediate);<br /> // assert quiz<br />1. Assert(x == intermediate);<br />2. Assert(intermediate == roundtripped);<br />3. Assert(normalized == roundtripped);<br />4. Assert(x == roundtripped); <br />}<br />
  92. 92. PatternState Relation<br />Observe a state change<br />void ContainedAfterAdd(string value) {<br />var list = new List&lt;string&gt;();<br />list.Add(value);<br /> // assert quiz<br />1. Assert(value != null);<br />2. Assert(list.Contains(value));<br />3. Assert(list.IndexOf(value) &lt; 0);<br />4. Assert(list[0] == value);<br />}<br />
  93. 93. PatternSame Observable Behavior<br />Given two methods f(x) and g(x), and a method b(y) that observes the result or the exception behavior of a method, assert that f(x) and g(x) have same observable behavior under b, i.e. b(f(x)) = b(g(x)) for all x.<br />public void ConcatsBehaveTheSame(<br /> string left, string right) <br />{<br />PexAssert.AreBehaviorsEqual(<br /> () =&gt; StringFormatter.ConcatV1(left, right),<br /> () =&gt; StringFormatter.ConcatV2(left, right));<br />}<br />
  94. 94. PatternAllowed Exception<br />Allowed exception -&gt; negative test case<br />[PexAllowedException(typeof(ArgumentException))]<br />void Test(object item) {<br />varfoo = new Foo(item) // validates item<br />// generated test (C#)[ExpectedException(typeof(ArgumentException))]void Test01() { Test(null); // argument check<br />}<br />
  95. 95. PatternReachability<br />Indicate which portions of a PUT should be reachable.<br />[PexAssertReachEventually]<br />public void Constructor(object input)<br />{<br /> new Foo(input);<br />PexAssert.ReachEventually(); <br />}<br />
  96. 96. PatternRegression Tests<br />Generated test asserts any observed value<br />Return value, out parameters, PexGoal<br />When code evolves, breaking changes in observable will be discovered<br />intAddTest(int a, int b) {<br /> return a + b; }<br />void AddTest01() {<br />varresult = AddTest(0, 0);<br />Assert.AreEqual(0, result);<br />}<br />
  97. 97. More Patterns<br />Read patterns paper:patterns.pdf<br />http://research.microsoft.com/Pex/patterns.pdf<br />
  98. 98. Limitationsand other Details<br />
  99. 99. The yellow event bar notifies about important events, including certain limitations<br />Event Bar<br />Click on issue kind for more information<br />
  100. 100. Events View<br />You should act on these events:<br />Refactor your code, or<br />tell Pex to ignore it in the future,<br />let Pex analyze (“instrument”) more code, if possible.<br />
  101. 101. Instrumenting more code<br /><ul><li>If Pex reports that some code was uninstrumented, you may tell Pex to instrument and analyze it(if possible)</li></li></ul><li>Instrumenting more code<br />Code instrumentation on Demand<br />Instrumentation has high performance overhead<br />Some parts of the code better ignored<br />Use PexInstrument… attributes<br />Pex will often suggest and insert those attributes for you<br />[assembly: PexInstrumentAssembly(“Foo”)]<br />
  102. 102. Pex understand managed .NET code only<br />Pex does not understand native code.<br />Problem if branching over values obtained from the environment<br />Pex may not automatically detect all such cases.<br />Testability<br />File System?<br />if (!File.Exists(f)) throw ...<br />
  103. 103. Hidden Complexity<br />Pex analyzes everyexecuted .NET instruction<br />Some used libraries may be surprisingly expensive to analyze<br />XML parsing<br />repeatedly converting data between different representations<br />void Sum(string[] A) {<br />var sum = “0”; <br />foreach(var a in A)<br /> sum = (int.Parse(a) + int.Parse(sum)).ToString();<br /> if(sum == “123”) throw new Exception(); <br />} <br />Don’t do this.<br />
  104. 104. Exploration Boundaries<br />Configurable bounds include:<br />TimeOut<br />MaxBranches<br />MaxCalls<br />MaxConditions<br />Number of conditions that depend on test inputs<br />MaxRuns<br />ConstraintSolverTimeOut<br />ConstraintSolverMemoryLimit<br />
  105. 105. Multi-threaded code<br />Unlike test inputs, thread-interleavings can normally not be controlled<br />Thus, Pex can only explore single-threaded code<br />Related approach to explore thread-schedules (but not input parameters) by controlling thread-scheduler: CHESShttp://research.microsoft.com/CHESS<br />
  106. 106. Lack of Test Oracle<br />Write assertions and Pex will try to break them<br />Without assertions, Pex can only find violations of runtime contracts causing NullReferenceException, IndexOutOfRangeException, etc.<br />Assertions leveraged in product and test code<br />Pex can leverage Code Contracts (discussed later)<br />
  107. 107. Exercise Limitations<br />Goal: Understand limitations.<br />Apply Pex to<br />if (File.Exists(fileName))<br /> throw new Exception(“found it”);<br />if (DateTime.Parse(s).Year == 2009)<br />throw new Exception(“found it”); <br />
  108. 108. Wrapping up<br />
  109. 109. What you learnedso far<br />The Definition of Test Unitaire<br />Unit Test Isolation through Moles<br />Unit Tests Isolation through Stubs<br />Stated-based Unit Tests with Behaved Types<br />Write Pex parameterized unit tests <br />
  110. 110. Thank you<br />http://research.microsoft.com/pex<br />

×