c# - How to implement FIND method of EF in Unit Test? -
i have web api 2.0 project unit testing. controllers have unit of work. unit of work contains numerous repositories various dbsets. have unity container in web api , using moq in test project. within various repositories, use find
method of entity framework locate entity based on it's key. additionally, using entity framework 6.0.
here general example of unit of work:
public class unitofwork { private iunitycontainer _container; public iunitycontainer container { { return _container ?? unityconfig.getconfiguredcontainer(); } } private applicationdbcontext _context; public applicationdbcontext context { { _context ?? container.resolve<applicationdbcontext>(); } } private genericrepository<examplemodel> _examplemodelrepository; public genericrepository<examplemodel> examplemodelrepository { { _examplemodelrepository ?? container.resolve<genericrepository<examplemodel>>(); } } //numerous other repositories , additional methods saving }
the problem running use find
method of linq queries in repositories. based on article, msdn: testing own test doubles (ef6 onwards), have create testdbset<examplemodel>
test find
method. thinking customizing code this:
namespace testingdemo { class testdbset : testdbset<tentity> { public override tentity find(params object[] keyvalues) { var id = (string)keyvalues.single(); return this.singleordefault(b => b.id == id); } } }
i figured have customize code tentity
type of base class has id property. that's theory, i'm not sure best way handle this.
so have 2 questions. approach listed above valid? if not, better approach overriding find
method in dbset
singleordefault
method? also, approach works if 1 primary key. if model has compound key of different types? assume have handle individually. okay, 3 questions?
to expand on comment earlier, i'll start proposed solution, , explain why.
your problem this: repositories have dependency on dbset<t>
. unable test repositories because depend on dbset<t>.find(int[])
, have decided substitute own variant of dbset<t>
called testdbset<t>
. unnecessary; dbset<t>
implements idbset<t>
. using moq, can cleanly create stub implementation of interface returns hard coded value.
class myrepository { public myrepository(idbset<mytype> dbset) { this.dbset = dbset; } mytype findentity(int id) { return this.dbset.find(id); } }
by switching dependency dbset<t>
idbset<t>
, test looks this:
public void myrepository_findentity_returnsexpectedentity() { var id = 5; var expectedentity = new mytype(); var dbset = mock.of<idbset<mytype>>(set => set.find(it.is<int>(id)) === expectedentity)); var repository = new myrepository(dbset); var result = repository.findentity(id); assert.aresame(expectedentity, result); }
there - clean test doesn't expose implementation details or deal nasty mocking of concrete classes , lets substitute out own version of idbset<mytype>
.
on side note, if find testing dbcontext
- don't. if have that, dbcontext
far stack , hurt if ever try , move away entity framework. create interface exposes functionality need dbcontext
, use instead.
note: used moq above. can use mocking framework, prefer moq.
if model has compound key (or has capability have different types of keys), things bit trickier. way solve introduce own interface. interface should consumed repositories, , implementation should adapter transform key composite type ef can deal with. you'd go this:
interface igenericdbset<tkeytype, tobjecttype> { tobjecttype find(tkeytype keytype); }
this translate under hood in implementation like:
class genericdbset<tkeytype,tobjecttype> { genericdbset(idbset<tobjecttype> dbset) { this.dbset = dbset; } tobjecttype find(tkeytype key) { // todo: convert key regular dbset can understand return this.dbset(key); } }
Comments
Post a Comment