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

Popular posts from this blog

How has firefox/gecko HTML+CSS rendering changed in version 38? -

javascript - Complex json ng-repeat -

jquery - Cloning of rows and columns from the old table into the new with colSpan and rowSpan -