c# - Rewriting OS-query method to become testable -
i'm going through our application's unit tests , improving/adding more of them. i'm quite (no, very) novice in unit testing/test-driven development , found following method wanted test. i'm stuck, , question if there's way rewrite testable?
public static bool is32bitos() { string os = (from x in new managementobjectsearcher("select * win32_operatingsystem").get().oftype<managementobject>() select x.getpropertyvalue("caption")).first().tostring().trim(); if (os.equals("microsoft windows xp professional")) { return true; } if (os.startswith("microsoft windows 7")) { string architecture = (from x in new managementobjectsearcher("select * win32_operatingsystem").get().oftype<managementobject>() select x.getpropertyvalue("osarchitecture")).first().tostring(); if (architecture == "64-bit") { return false; } } return true; }
your method has 3 responsibilities:
- management object searcher creation
- os , architecture retrieval
- os verification
to enable testing i'd add in assemblyinfo.cs line similar this:
[assembly: internalsvisibleto("your.test.project")]
so protected methods visible test project not freely available clients. i'd rewrite method os verification separated:
//acceptance test method public static bool is32bitos() { var managementobjects = new managementobjectsearcher("select * win32_operatingsystem").get().oftype<managementobject>(); string os = (from x in managementobjects select x.getpropertyvalue("caption")).first().tostring().trim(); string architecture = (from x in managementobjects select x.getpropertyvalue("osarchitecture")).first().tostring(); return is32bitos(os, architecture); } //unit test method internal static bool is32bitos(string os, string architecture) { if (os.equals("microsoft windows xp professional")) { return true; } if (os.startswith("microsoft windows 7")) { string architecture = archretriever(); if (architecture == "64-bit") { return false; } } return true; }
now have separated concerns i'd unit test should verify is32bitos behaviour while acceptance test should verify end end stack. in fact have little value in unit testing
(from x in new managementobjectsearcher("select * win32_operatingsystem").get().oftype<managementobject>() select x.getpropertyvalue("caption")).first().tostring().trim();
retrieves os string while real value resides in usage of info determine if os 32 bit.
an alternative wrap things in interfaces , use mocking frameworks apply functional programming here llewellyn falco's peel , slice technique , here arlo belshee's no mocks approach. instead of method like:
public static bool is32bitos(iretrieveosandarchitecture roa) { string os = roa.getos(); string architecture = roa.getarchitecure(); return is32bitos(os, architecture); }
you use like:
public static bool is32bitos(func<managementobjectsearcher, string> osretriever, func<managementobjectsearcher, string> archretriever, managementobjectsearcher searcher) { string os = osretriever(searcher); string architecture = archretriever(searcher); return is32bitos(os, architecture); }
its client method be:
public static bool is32bitos() { var searcher = new managementobjectsearcher("select * win32_operatingsystem"); return is32bit((s)=>{ (from x in s.get().oftype<managementobject>() select x.getpropertyvalue("caption")).first().tostring().trim()}, (s)=>{ (from x in s.get().oftype<managementobject>() select x.getpropertyvalue("osarchitecture")).first().tostring();}, searcher); }
notice while testing cases of interfaces , functional not using real managementobjectsearcher external dependency; in mockist approach you'll use mock object in functional programming you'll pass in different lambda expression should return os , architecture strings.
there's still responsibility left method , creation of managementobjectsearcher; resolve dependency can:
- pass parameter of method
- make field of class initilized @ construction time
Comments
Post a Comment