instead of entity framework, using enterprise library perform data operations.
the following sample bl method used update person culture. don't have idea how write unit test these kind of methods.
public static culture updatepersonculture(guid userid, culture culture) { try { if (userid == guid.empty) throw new exception("user id should not empty"); databaseproviderfactory factory = new databaseproviderfactory(); database database = factory.createdefault(); using (dbconnection dbconnection = database.createconnection()) { if (dbconnection.state == connectionstate.closed) dbconnection.open(); dbcommand dbcommand = database.getstoredproccommand("usp_updatepersonculture"); database.discoverparameters(dbcommand); dbcommand.parameters["@userid"].value = userid; dbcommand.parameters["@cultureid"].value = culture.id; dataset dataset = database.executedataset(dbcommand); return bldatapopulation.populatecultures(dataset.tables[0]).firstordefault(); } } catch (exception exception) { throw bllogger.log(exception); } }
a unit test means given input, code behave in known behavior , produces known-in-advance output. should execute fast because executes (could executed whenever code changes ncrunch). unit test scope should class.
integration tests tests test @ higher scope. test whether several class, part of programs, or different programs work together. however, stability of these tests (since rely on external components fail time time), definition of "working well" remains @ best blurry, , maintenance costs of such tests, make added value of integration tests low. in fact, saw projects without of them or integration tests decommissioned because of maintenance costs.
however, can limit untestable code minimum:
separate interfaces implementation: isolate external resource (like file i/o or database) access behind interface hiding implementation complexity.
avoid static code, because it's impossible unit test static code. implementation rigged in static classes. if static code calls external resources cannot control input , output , cannot test result then.
learn refactor: legacy code can handled if build skills so. isolate small piece of code, write unit test it, , replace more robust code.
test first or test driven development, tdd can make newly written code testable beginning. it's process involving writing expectations have given class before writing implementation of class.
behavior driven development or bdd: when have in basket, customer requests, cannot go lowest level required unit tests. can use tools specflow build requirements grammar , transform tests.
in order write unit tests , refactor legacy untestable code, you'll need ioc tools (since constructors signatures have tendency grow theses techniques) , mock framework moq in order simulate interfaces you'll add while not binding them implementation.
for example in case, i've refactored class containing method test:
public class classtotest : iinterfacetotest { private readonly ibllogger _logger; private readonly ibldatapopulation _bldatapopulation; private readonly idatabase _database; public classtotest(ibllogger logger, ibldatapopulation bldatapopulation, idatabase database) { _logger = logger; _bldatapopulation = bldatapopulation; _database = database; } // cannot static if want // unit test classes depending on one. public culture updatepersonculture(guid userid, culture culture) { try { if (userid == guid.empty) throw new exception("user id should not empty"); var dataset = _database.provideculturemappings(userid, culture); return _bldatapopulation.populatecultures(dataset.tables[0]).firstordefault(); } catch (exception exception) { throw _logger.log(exception); } } }
the interfaces added:
public interface idatabase { dataset provideculturemappings(guid userid, culture culture); } public interface ibllogger { exception log(exception exception); } public interface ibldatapopulation { ienumerable<culture> populatecultures(datatable datatable); }
the result:
[testfixture] public class databaseunittest { [test] public void test() { var logger = new mock<ibllogger>(mockbehavior.strict); var bldatapopulation = new mock<ibldatapopulation>(mockbehavior.strict); var database = new mock<idatabase>(mockbehavior.strict); var totest = new classtotest(logger.object, bldatapopulation.object, database.object); var userid = guid.newguid(); var culture = new culture{id = "myid"}; var dataset = new dataset(); var table = new datatable(); dataset.tables.add(table); database.setup(x => x.provideculturemappings(userid, culture)).returns(dataset); var culturelist = new list<culture> {culture, new culture {id = "anotherculture"}}; bldatapopulation.setup(x => x.populatecultures(table)).returns(culturelist); var result = totest.updatepersonculture(userid, culture); assert.areequal(result.id, culture.id); } }
and bonus non testable class:
public class database : idatabase { public dataset provideculturemappings(guid userid, culture culture) { databaseproviderfactory factory = new databaseproviderfactory(); database database = factory.createdefault(); using (dbconnection dbconnection = database.createconnection()) { if (dbconnection.state == connectionstate.closed) dbconnection.open(); dbcommand dbcommand = database.getstoredproccommand("usp_updatepersonculture"); database.discoverparameters(dbcommand); dbcommand.parameters["@userid"].value = userid; dbcommand.parameters["@cultureid"].value = culture.id; dataset dataset = database.executedataset(dbcommand); return dataset; } } private dataset executedataset(dbcommand dbcommand) { throw new notimplementedexception(); } private void discoverparameters(dbcommand dbcommand) { throw new notimplementedexception(); } private dbcommand getstoredproccommand(string uspupdatepersonculture) { throw new notimplementedexception(); } private dbconnection createconnection() { throw new notimplementedexception(); } }
Comments
Post a Comment