html5-img
1 / 103

Parameterized Unit Testing

ICTSS’11 Tutorial. Parameterized Unit Testing. Nikolai Tillmann Microsoft Research. Outline. First part: 14:00 - 15:00pm Second part: 15:30 - 17:00pm. Outline. Unit Testing Isolation Parameterized Unit Testing Data Generation by Dynamic Symbolic Execution Patterns

sanjiv
Download Presentation

Parameterized Unit Testing

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. ICTSS’11 Tutorial Parameterized Unit Testing • Nikolai Tillmann • Microsoft Research

  2. Outline • First part: 14:00 - 15:00pm • Second part: 15:30 - 17:00pm

  3. Outline • Unit Testing • Isolation • Parameterized Unit Testing • Data Generation byDynamic Symbolic Execution • Patterns • Limitations and other Details

  4. About the exercises… • Interactive: http://pexforfun.com • Demos: Pex for Visual Studiohttp://research.microsoft.com/pex • Requires Windows, .NET 2.0 or 4.0, ideally Visual Studio 2008 / 2010

  5. Unit Testing

  6. Quiz: Unit testing • What is a unit test?

  7. Unit Testing • A unit test is a small program with assertions • Test a single (small) unit of code • Let’s play a game! void AddAndCount() { var list = new List(); list.Add(3); Assert.AreEqual(1, list.Count); }

  8. The Code Under Test string ReadFooValue() { string[] lines = File.ReadAllLines(@"t:\myapp.ini"); foreach(var line in lines){ intindex = line.IndexOf('='); string name = line.Substring(index); if (name == "Foo") { string value = line.Substring(index + 1); return value; } } return null; } t:\myapp.ini A=B Foo=C C=D

  9. Quiz: Coverage • How much block coverage do we need? • 50% • 80% • 100% • Block coverage alone is not enough

  10. Quiz: Coverage • How much block coverage do we need? • 50% • 80% • 100% • Block coverage alone is not enough

  11. Quiz: Coverage [TestMethod] void ExistingFoo() { File.WriteAllLines(@"t:\myapp.ini",new string[]{“Foo=b”}); Reader.ReadFooValue();} • Do we need more tests to get 100% cov.? [TestMethod] void MissingFoo() { File.WriteAllLines(@"t:\myapp.ini",new string[0]); Reader.ReadFooValue();}

  12. Quiz: Assertions • Why write Assertions (or not)? • Documentation • Double check your program • Please your manager • Prevent future bugs • Validate user inputs • Catch errors early

  13. Quiz: Assertions • Why write Assertions (or not)? • Documentation • Double check your program • Please your manager • Prevent future bugs • Validate user inputs • Catch errors early

  14. Quiz: Assertions • Which Assertions should you write? • Assert.IsTrue(value == “b”); • Assert.IsTrue(value == null); • Assert.IsTrue(String.IsNullOrEmpty(value)) • Assert.IsTrue(false); • No assertions [TestMethod] void MissingFoo() { File.WriteAllLines(@"t:\myapp.ini",new string[]{“a=b”}); string value = Reader.ReadFooValue(); Assert.IsTrue(????);}

  15. Quiz: Assertions • Which Assertions should you write? • Assert.IsTrue(value == “b”); • Assert.IsTrue(value == null); • Assert.IsTrue(String.IsNullOrEmpty(value)) • Assert.IsTrue(false); • No assertions [TestMethod] void MissingFoo() { File.WriteAllLines(@"t:\myapp.ini",new string[]{“a=b”}); string value = Reader.ReadFooValue(); Assert.IsTrue(????);}

  16. Quiz: Coverage +Assertions • What gives you confidence in the code? • High coverage, no assertions • Low coverage, many assertions • High coverage, many assertions • Low coverage, no assertions • I wrote it

  17. Quiz: Coverage +Assertions • What gives you confidence in the code? • High coverage, few assertions • Low coverage, many assertions • High coverage, many assertions • Low coverage, no assertions • I wrote it

  18. The Code Under Test string ReadFooValue() { string[] lines = File.ReadAllLines(@"t:\myapp.ini"); foreach(var line in lines){ intindex = line.IndexOf('='); string name = line.Substring(index); if (name == "Foo") { string value = line.Substring(index + 1); return value; } } return null; }

  19. Quiz: Isolation string ReadFooValue() { string[] lines = File.ReadAllLines(@"t:\myapp.ini"); ... } • In the example, what are the external dependencies? • Network Share • Local Disk • No file system, all in memory

  20. Quiz: Isolation string ReadFooValue() { string[] lines = File.ReadAllLines(@"t:\myapp.ini"); ... } • In the example, what are the external dependencies? • Network Share • Local Disk • No file system, all in memory

  21. Quiz: Isolation • What is the problem with a Local Disk? • Mapping already exists • Cannot run tests concurrently • Disk full • Access rights

  22. Quiz: Isolation • What is the problem with a Local Disk? • Mapping already exists • Cannot run tests concurrently • Disk full • Access rights

  23. Quiz: Isolation • How do you mitigate the Local Disk issues? • Always run on the same machine, same hardware, same credentials, same time, same temperature, same solar system configuration • Refactoring: use Streams • Refactoring: introduce IFileSystem • Refactoring: pass the lines as parameter • Change implementation of File.ReadAllLines

  24. Quiz: Isolation • How do you mitigate the Local Disk issues? • Always run on the same machine, same hardware, same credentials, same time, same temperature, same solar system configuration • Refactoring: use Streams • Refactoring: introduce IFileSystem • Refactoring: pass the lines as parameter • Change implementation of File.ReadAllLines

  25. Quiz: Definition of Unit Test • What is a Unit Test? • A Unit Test is a program that runs fast the code under test, without environment dependencies, with assertions. • What is a Unit Test Suite? • A set of Unit Tests which achieves high code coverage

  26. Isolation

  27. Dependency hell var lines = File.ReadAllLines(@"t:\v.ini"); • How do you changeFile.ReadAllLines? • Override static method • Changing the .NET Framework source code(and recompiling it) • Rewrite application in JavaScript • Code instrumentation

  28. Replace any .NET methodwith a delegate var lines = File.ReadAllLines(@"t:\myapp.ini"); What if we could replace File.ReadAllLines? File.ReadAllLines = delegate(string fn) MFile.ReadAllLinesString= delegate(string fn) { return new string[0]; }; Moles

  29. Motivation for Moles • Why another isolation framework? • Specifically designed to enable Pex • Simple, well-defined semantics • “Replace any .NET method”

  30. Mole Types Code Generation // System.IO public static class File{ public static string[] ReadAllLines(string fn);} // System.IO.Moles public class MFile{ public static Func<string, string[]> ReadAllLinesString; } // delegate R Func<T, R>(T t);

  31. Injecting Detours at Runtime // System.IO public static class File { public static string[] ReadAllLines(string fn) { if (MFile.ReadAllLinesString != null) return MFile.ReadAllLines(fn); … original code } } Automatically injected at runtime

  32. MolesDemo • Start fromReadFooValueproblem • Create test project • Add moles for mscorlib • Write test using moles • Run test • Debug test • You can pick up project fromReadFooValueIsolation\ReadFooValueIsolation.sln

  33. Quiz: Moles Usage • When should you use Moles (and not)? • Always use Moles to solve isolation issues • With Moles, one does not need to use interfaces anymore • Moles only should be used for 3rd party API, use interfaces for isolation in your APIs • Moles can be used in production code • Moles lets you get away with untestable APIs • Moles make test cases more robust • With Moles, you do not need integration tests anymore • Moles make tests easier to understand • Moles is for poor programmers, real programmers rely on interfaces

  34. Quiz: Moles Usage • When should you use Moles (and not)? • Always use Moles to solve isolation issues • With Moles, one does not need to use interfaces anymore • Moles only should be used for 3rd party API, use interfaces for isolation in your APIs • Moles can be used in production code • Moles lets you get away with untestable APIs • Moles make test cases more robust • With Moles, you do not need integration tests anymore • Moles make tests easier to understand • Moles is for poor programmers, real programmers rely on interfaces

  35. Exercise (Optional / homework) • Step-by-step tutorial: • research.microsoft.com/documentation.aspx • “Unit Testing with Microsoft Moles” • “Unit Testing SharePoint Foundation with Microsoft Pex and Moles”

  36. What you learnedso far • The Definition of Unit Testing • Unit Test Isolation • Identify External Dependencies • Replace each External API with your delegate

  37. Parameterized Unit Testing

  38. The Recipe of Unit Testing • Three essential ingredients: • Data • Method Sequence • Assertions void AddAndCount() { int item = 3; var list = new List(); list.Add(item); var count = list.Count; Assert.AreEqual(1, count); }

  39. Quiz: list.Add(???) list.Add(???); • Which value matters? • 0 • 1 • int.MaxValue, int.MinValue • -1 • 1000 • it does not matter • I don’t know until I read the code

  40. Parameterized Unit Testing void AddAndCount(List list, int item) { var count = list.Count; list.Add(item); Assert.AreEqual(count + 1, list.Count); } • Parameterized Unit Test = Unit Test with Parameters • Separation of concerns • Specification of behavior • Data to achieve coverage for any list, for any item, … adding 1 item increments Count by 1

  41. Parameterized Unit Tests areAlgebraic Specifications • A Parameterized Unit Test can be read as a universally quantified, conditional axiom. void ReadWrite(string name, string data) {Assume.IsTrue(name != null && data != null); Write(name, data);varreadData = Read(name); Assert.AreEqual(data, readData); } forall. string name, string data: name not_equal null and data not_equal null implies equals( ReadResource(name,WriteResource(name,data)), data)

  42. Parameterized Unit Testingis going mainstream Parameterized Unit Tests (PUTs) commonly supported by various test frameworks • .NET: Supported by .NET test frameworks • http://www.mbunit.com/ • http://www.nunit.org/ • … • Java: Supported by JUnit 4.X • http://www.junit.org/ Generating test inputs for PUTs supported by tools • .NET: Supported by Microsoft Research Pex • http://research.microsoft.com/Pex/ • Java: Supported by AgitarAgitarOne • http://www.agitar.com/

  43. Problem We cannot execute parameterized unit tests without data. Where does the data come from? • Random data generator • Real customer data • Ranges • Some values hand-picked by dev/tester

  44. Data Generationby Dynamic Symbolic Execution

  45. Data Generation Challenge Goal: Given a program with a set of input parameters, automatically generate a set of input values that, upon execution, will exercise as many statements as possible How would you do it?

  46. Dynamic Symbolic ExecutionCombines many ideas Combines ideas from • symbolic execution • to capture behavior symbolically • model checking • to perform systematic bounded state space exploration • testing • to monitor and check concrete behavior • constraint solving • to find inputs

  47. Dynamic Symbolic ExecutionThe high-level algorithm • This choice decides search order • Search order decides how quickwe can achieve high code coverage! • Incomplete constraint-solver leads tounder-approximation Combines concrete and symbolic execution Algorithm: Set J := ∅ (J is set of already analyzed program inputs) Loop Choose program input i ∉ J (stop if no such i can be found) Output i Execute P(i); record path condition C (in particular, C(i) holds) Set J := J ∪ C (viewing C as the set { i | C(i ) } ) End loop Loop does not terminate if number of execution paths is infinite (in the presence of loops/recursion)

  48. Dynamic Symbolic ExecutionExample Choose next path • Code to generate inputs for: Solve Execute&Monitor void CoverMe(int[] a) { if (a == null) return; if (a.Length > 0) if (a[0] == 1234567890) throw new Exception("bug"); } a==null F T a.Length>0 T F Done: There is no path left. a[0]==123… F T Observed constraints a==null a!=null && !(a.Length>0) a!=null && a.Length>0 && a[0]!=1234567890 a!=null && a.Length>0 && a[0]==1234567890 Data null {} {0} {123…} Constraints to solve a!=null a!=null && a.Length>0 a!=null && a.Length>0 && a[0]==1234567890

  49. http://pex4fun.com/CoverMe

More Related