dotnet unit testing training
TRANSCRIPT
.NET Unit Test Session
Prepared By:Tom Tang
Dec. 2010 (v1.0)
●Concept●Implementation●Challenge●Automation – Hudson●Professional guideline●Q & A and sharing
CONCEPTAbout unit test
Concept
●Why unit test?oPrevent side-effect as less as possible.o Improve code quality and stability.o Improve maintainability.oConsolidate design.oSave time from manual testing in the future.oDescribe the usage of your libraries and classes.
Concept
●How unit test help our code quality?When you are doing implementation…oHow do you confirm your design “loosely-coupled” well
enough?oHow do you keep the correct behavior of the class you’re
updating?oHow do you ensure you have fixed the bug?oHow do you describe some tricky design / use case?
●Key rule: Cut off all dependency!!!1.Human interaction dependency(UI)2.Library dependency3.Sequence dependency4.Environment dependency5.Hierarchy dependencyRemember, it’s not only testing, it’s “UNIT” testing.
Concept
●Cost - You must pay, then gain…oWrite code to verify code: More code, more bug.oCost much more time than real functional implementation.oMuch more code have to be maintained.
Exchange short-term effort for long-term benefit.
Concept
●Mind construction:oDo not think coverage, JUST DO IT®.oTest case shall keep growing, never think approach all at one
time.o It saves the future, not save the present.oDoing unit test is never easy, so it make quality competitive.
There’s no silver bullet.
IMPLEMENTATIONWhat to do? How to do?
Implementation
Introduce Visual Studio built-in unit test tool:
Implementation
Best practice policy:1.Every public entry must have at least 1 unit test case.2.Pair programming technique –
One implement test case, the other one implement functionality.3.TDD (Not DDT) –
Test-Driven Development – Implement test case before implement functional code.
Implementation
TDD life-cycle:
Define interface(empty class)
Write test code through the
interfaceTest Failure.
Implement functional class.
Pass test case
Commit
Developer A
Developer B
Implementation
Unit test running life-cycle for a class:
ClassInitialize
TestInitialize
TestMethod
TestCleanup
ClassCleanup
TestInitialize
TestMethod
TestCleanup
Implementation
How to do a useful test case:
●Awful, but at least it prevents run-time exception in some case.●Better one:
Implementation
How to do a useful test case:● Is this one good idea?
Better to avoid this style, keep the meaning of “unit” in mind.
Implementation
How to do a useful test case:The other bad sample…Some genius developer write a perfect bug-free implementation, how come it failed to pass test case:
???
Implementation
How to do a useful test case:The other bad sample…Updating test case assume there’s an existing member…After running the creating test case, the updating test case passed.
There’s a test case sequential dependency.
Once a test case can’t be executed alone, it’s NOT an unit test case.
Implementation
How to do a useful test case:How to make the case better…Preparing its own precondition is every unit test case’s “Ownership”!
Implementation
How to do a useful test case:How to test error handling…FunSpec: Once user try to create duplicated member, we shall throw exception to alert user.
ImplementationHow to do a useful test case:How to follow up?
1.Don’t do new unit-test case by only coverage reason.2.Build new test case by JIRA Ticket.
Implementation
Ticket unit test life-cycle:
Got ticket
Write test code to reproduce
the caseTest Failure.
Fix the bug.
Pass test case
Commit
QA verify
Implementation
Ticket unit test life-cycle:●Example – PMO-3357
Implementation
Ticket unit test life-cycle:●Example – PMO-3357
Implementation
Promotion unit test demo:
Implementation
Promotion unit test demo:
CHALLENGETricky technique to cut-off dependency
ChallengeHow to cut-off dependency?Use MVC design to separate logic and UIprivate void OnButtonClick(EventArg e) { if (txtBox1.Text == “ABC”) { txtAnswer.Text = “XXX”; } else if (txtBox1.Text == “DEF”) { txtAnswer.Text = “YYY”; }}
Change code design like this:private void OnButtonClick(EventArg e) { txtAnswer.Text = new Controller().GetAnswer(txtText1.Text);}// controller class can be unit tested.public class Controller { public string GetAnswer(string input) { if (input == “ABC”) { return “XXX”; } else if (input == “DEF”) { return “YYY”; } }}
Challenge
How to cut-off dependency?Library dependency:You want to test “ClassA”, but “ClassA” associated with “ClassB”, and you don’t want to involve “ClassB” in this test case.
public class MathTool { public int AddNumber(int a, int b) { BackendService service = new BackendService(); // Dependency happen here. return service.AddNumberWebservice(a, b); }}public class BackendService { public int AddNumberWebservice(int a, int b) { HttpClient client = new HttpClient(); client.Url = "http://LiveMathTeacher.spi/AddNumber.asmx"; client.SubmitData(a, b); int c = (int)client.GetResponseData(); return c; }}
Challenge
public class BackendService : IService { public int AddNumberWebservice(int a, int b) { HttpClient client = new HttpClient(); client.Url = "http://LiveMathTeacher.spi/AddNumber.asmx"; client.SubmitData(a, b); int c = (int)client.GetResponseData(); return c; }}public class MockService : IService { public int AddNumberWebservice(int a, int b) { return a + b; }}
Challenge
How to cut-off dependency?Environment Dependency:
●If your class must access environment resource, like container(IIS)…public string GetLoginUserName() { if (CheckToken((string)Request[“token”])) // It accesses HTTP request resource return (string)Session[“UserName”]; // It accesses IIS memory}
Encapsulate those resource into tool classes: public class SessionManager {#if(UNIT_TEST) // Use Dictionary structure to replace Session in unit-test public static Dictionary<string, object> Session = new Dictionary<string, object>(); #else public static HttpSessionState Session = HttpContext.Current.Session;#endif}
Use similar class for switching:public string GetLoginUserName() { if (CheckToken((string)RequestManager.Request[“token”])) return (string)SessionManager.Session[“UserName”]; }
Challenge
How to cut-off dependency?Hierarchy Dependency:
●If your class inherits from the other class which you don’t have source(3rd party library…etc) and the base class would access any other dependency that you can’t cut-off…
Examples:// This class inherits from System.ServiceProcess.ServiceBase, its constructor will auto access environment resource.using System.ServiceProcess;public class MyService : ServiceBase { }
// This class inherits from System.Web.UI.Page, it’s ASP.NET class and access IIS resource.using System.Web.UI;public class MyPage : Page { }
Challenge
AUTOMATION - HUDSONUnit test with automation
Automation - hudson
Integrate unit test with Hudson:Visit this URL for sample: http://xxx.xxx.xxx/view/banana%20DEV/job/backend.UnitTest/
Automation - hudson
Integrate unit test with Hudson:
Automation - hudson
Integrate unit test with Hudson:
PROFESSIONAL GUIDELINESample review
Professional guideline
Extract the summary from the book “Pragmatic Unit Test”:
General Principles:1.Test anything that might break2.Test everything that does break3.New code is guilty until proven innocent4.Write at least as much test code as
production code5.Run local tests with each compile6.Run all tests before check-in to repository
Questions to Ask:1.If the code ran correctly, how would I know?2.How am I going to test this?3.What else can go wrong?4.Could this same kind of problem happen
anywhere else?
Professional guide line
Extract the summary from the book “Pragmatic Unit Test”:
What to Test: Use Your RIGHT-BICEP1.Are the results right?2.Are all the boundary conditions CORRECT?3.Can you check inverse relationships?4.Can you cross-check results using other
means?5.Can you force error conditions to happen?6.Are performance characteristics within
bounds?
Good tests are A TRIP1.Automatic2.Thorough3.Repeatable4.Independent5.Professional
Professional guide line
Extract the summary from the book “Pragmatic Unit Test”:
CORRECT Boundary Conditions1.Conformance - Does the value conform to an
expected format?2.Ordering - Is the set of values ordered or
unordered as appropriate?3.Range - Is the value within reasonable
minimum and maximum values?4.Reference - Does the code reference
anything external that isn‘t under direct control of the code itself?
5.Existence - Does the value exist? (e.g., is non-null, non-zero, present in a set, etc.)
6.Cardinality - Are there exactly enough values?7.Time (absolute and relative) - Is everything
happening in order? At the right time? In time?
Q & A AND SHARINGHow to configure Strawberry
THANKSThe end