entity framework - Using DbContext in MS unit test -


i not sure how fit ef business logic tests. let me give example of how works @ runtime (no testing, regular application run):

context.set<t>.add(instance); 

when add entity using above generic method, instance added context, , ef fixes navigation properties behind scenes. example, if exists [instance.parent] property, , [parent.instances] collection property (1-to-many relationship), ef automatically add instance parent.instances collection behind scenes.

my code depends on [parent.instances] collection, , if empty, fail. when writing unit tests using ms testing framework, how can reuse power of ef, can still behind-the-scenes job, uaing memory data storage, , not actual database? not interested whether ef added, modified or deleted in database, interested in getting ef magic on in-memory sets.

i've been doing mock dbcontext , mock dbset i've created. store test data in memory , allow of standard things can on dbset.

your code acquires dbcontext have changed acquires mockdbcontext when running under unit test. can determine if running under mstest following code:

public static bool isinunittest {         {         return appdomain.currentdomain.getassemblies()             .any(assembly =>                  assembly.fullname.startswith(                      "microsoft.visualstudio.qualitytools.unittestframework"));     } } 

here code mockdbcontext:

using system; using system.collections.generic; using system.data.common; using system.data.entity; using system.data.entity.core.objects; using system.data.entity.infrastructure; using system.threading; using system.threading.tasks;  namespace consoleapplication5 {     // productiondbcontext dbcontext class     // generated entity framework     public class mockdbcontext: productiondbcontext     {         public mockdbcontext()         {             loadfakedata();         }          // entities (for we'll provide mockdbset implementation          // , test data)         public override dbset<account> accounts { get; set; }         public override dbset<accountgenlink> accountgenlinks { get; set; }         public override dbset<accountpermit> accountpermits { get; set; }         public override dbset<acctdocgenlink> acctdocgenlinks { get; set; }          // dbcontext method overrides         private int internalsavechanges()         {             // return 0 in mock             return 0;         }          public override int savechanges()         {             return internalsavechanges();         }          public override task<int> savechangesasync()         {             return task.fromresult(internalsavechanges());         }          public override task<int> savechangesasync(cancellationtoken cancellationtoken)         {             // ignore cancellation token in mock             return savechangesasync();         }          private void loadfakedata()         {             // tables             accounts = new mockdbset<account>(this);             accounts.addrange(new list<account>             {                 new account                 {                     ssn_ein = "123456789", code = "a", accttype = "cd",                      acctnumber = "1", pending = false, bankofficer1 = string.empty,                      bankofficer2 = null, branch = 0, type = "18", drm_rate_code = "18",                      officer_code = string.empty, open_date = new datetime(2010, 6, 8),                      maturity_date = new datetime(2010, 11, 8), hostacctactive = true,                      effectiveacctstatus = "a"                 },                 new account                 {                     ssn_ein = "123456789", code = "a", accttype = "dd",                      acctnumber = "00001234", pending = false, bankofficer1 = "bck",                      bankofficer2 = string.empty, branch = 0, type = "05", drm_rate_code = "00",                      officer_code = "djt", open_date = new datetime(1998, 9, 14),                      maturity_date = null, hostacctactive = true,                      effectiveacctstatus = "a"                 },                 new account                 {                     ssn_ein = "123456789", code = "a", accttype = "ln", acctnumber = "1",                      pending = false, bankofficer1 = "lmp", bankofficer2 = string.empty,                      branch = 0, type = "7", drm_rate_code = null, officer_code = string.empty,                     open_date = new datetime(2001, 10, 24),                      maturity_date = new datetime(2008, 5, 2), hostacctactive = true,                      effectiveacctstatus = "a"                 }             });              accountgenlinks = new mockdbset<accountgenlink>(this);             accountgenlinks.addrange(new list<accountgenlink>             {                 // add test data here if needed             });              accountpermits = new mockdbset<accountpermit>(this);             accountpermits.addrange(new list<accountpermit>             {                 // add test data here if needed             });              acctdoclinks = new mockdbset<acctdoclink>(this);             acctdoclinks.addrange(new list<acctdoclink>             {                 new acctdoclink { id = 1, ssn_ein = "123456789", code = "a", accttype = "dd",                                    acctnumber = "00001234", docid = 50, doctype = 5 },                 new acctdoclink { id = 25, ssn_ein = "123456789", code = "6", accttype = "cd",                                    acctnumber = "1", docid = 6750, doctype = 5 }             });         }     } } 

and here code mockdbset:

using system; using system.collections; using system.collections.generic; using system.collections.objectmodel; using system.data.entity; using system.data.entity.core.metadata.edm; using system.data.entity.infrastructure; using system.linq; using system.linq.expressions; using system.threading; using system.threading.tasks;  namespace consoleapplication5 {     public sealed class mockdbset<tentity> : dbset<tentity>, iqueryable,          ienumerable<tentity>, idbasyncenumerable<tentity> tentity : class     {         public mockdbset(mockdbcontext context)         {             // entity set entity             // used when figure out whether generate             // identity values             entityset = ((iobjectcontextadapter) context).objectcontext                 .metadataworkspace                 .getitems<entitycontainer>(dataspace.sspace).first()                 .baseentitysets                 .firstordefault(item => item.name == typeof(tentity).name);              data = new observablecollection<tentity>();             query = data.asqueryable();         }          private observablecollection<tentity> data { get; set; }          type iqueryable.elementtype         {             { return query.elementtype; }         }          private entitysetbase entityset { get; set; }          expression iqueryable.expression         {             { return query.expression; }         }          ienumerator ienumerable.getenumerator()         {             return data.getenumerator();         }          public override observablecollection<tentity> local         {             { return data; }         }          iqueryprovider iqueryable.provider         {             { return new mockdbasyncqueryprovider<tentity>(query.provider); }         }          private iqueryable query { get; set; }          public override tentity add(tentity entity)         {             generateidentitycolumnvalues(entity);             data.add(entity);             return entity;         }          public override ienumerable<tentity> addrange(ienumerable<tentity> entities)         {             foreach (var entity in entities)                 add(entity);             return entities;         }          public override tentity attach(tentity entity)         {             return add(entity);         }          public override tentity create()         {             return activator.createinstance<tentity>();         }          public override tderivedentity create<tderivedentity>()         {             return activator.createinstance<tderivedentity>();         }          public override tentity find(params object[] keyvalues)         {             throw new notsupportedexception();         }          public override task<tentity> findasync(params object[] keyvalues)         {             return findasync(cancellationtoken.none, keyvalues);         }          public override task<tentity> findasync(cancellationtoken cancellationtoken, params object[] keyvalues)         {             throw new notsupportedexception();         }          private void generateidentitycolumnvalues(tentity entity)         {             // purpose of method, called when adding row,              // ensure identity column values initialized              // before performing add.  if making "real" entity framework              // add() call, task handled data provider ,              // value(s) propagated entity.  in case              // of mock, there nothing that, have make             // at-least token effort ensure columns initialized.              // in sql server, identity column can of 1 of following              // data types:  tinyint, smallint, int, bigint, decimal (with scale of 0),              // or numeric (with scale of 0);  method handles integer types              // (the others typically not used).             foreach (var member in entityset.elementtype.members.tolist())             {                 if (member.isstoregeneratedidentity)                 {                     // ok, we've got live one; our thing.                     //                     // note we'll current value of column and,                      // if nonzero, we'll leave alone.  because                      // test data in our mock dbcontext provides values                      // identity columns , many of values foreign keys                      // in other entities (where provide test data).  don't                     // want disturb existing relationships defined in test data.                     type columndatatype = null;                     foreach (var metadataproperty in member.typeusage.edmtype.metadataproperties.tolist())                     {                         if (metadataproperty.name != "primitivetypekind")                             continue;                         switch ((primitivetypekind)metadataproperty.value)                         {                             case primitivetypekind.sbyte:                                 columndatatype = typeof(sbyte);                                 break;                             case primitivetypekind.int16:                                 columndatatype = typeof(int16);                                 break;                             case primitivetypekind.int32:                                 columndatatype = typeof(int32);                                 break;                             case primitivetypekind.int64:                                 columndatatype = typeof(int64);                                 break;                             default:                                 throw new invalidoperationexception();                         }                          var identitycolumngetter = entity.gettype().getproperty(member.name).getgetmethod();                         var identitycolumnsetter = entity.gettype().getproperty(member.name).getsetmethod();                          int64 specifiedcolumnvalue = 0;                         switch (columndatatype.name)                         {                             case "sbyte":                                 specifiedcolumnvalue = (sbyte)identitycolumngetter.invoke(entity, null);                                 break;                             case "int16":                                 specifiedcolumnvalue = (int16)identitycolumngetter.invoke(entity, null);                                 break;                             case "int32":                                 specifiedcolumnvalue = (int32)identitycolumngetter.invoke(entity, null);                                 break;                             case "int64":                                 specifiedcolumnvalue = (int64)identitycolumngetter.invoke(entity, null);                                 break;                         }                         if (specifiedcolumnvalue != 0)                             break;                          int64 maxexistingcolumnvalue = 0;                          switch (columndatatype.name)                         {                             case "sbyte":                                 foreach (var item in local.tolist())                                     maxexistingcolumnvalue = math.max(maxexistingcolumnvalue, (sbyte)identitycolumngetter.invoke(item, null));                                 identitycolumnsetter.invoke(entity, new object[] { (sbyte)(++maxexistingcolumnvalue) });                                 break;                             case "int16":                                 foreach (var item in local.tolist())                                     maxexistingcolumnvalue = math.max(maxexistingcolumnvalue, (int16)identitycolumngetter.invoke(item, null));                                 identitycolumnsetter.invoke(entity, new object[] { (int16)(++maxexistingcolumnvalue) });                                 break;                             case "int32":                                 foreach (var item in local.tolist())                                     maxexistingcolumnvalue = math.max(maxexistingcolumnvalue, (int32)identitycolumngetter.invoke(item, null));                                 identitycolumnsetter.invoke(entity, new object[] { (int32)(++maxexistingcolumnvalue) });                                 break;                             case "int64":                                 foreach (var item in local.tolist())                                     maxexistingcolumnvalue = math.max(maxexistingcolumnvalue, (int64)identitycolumngetter.invoke(item, null));                                 identitycolumnsetter.invoke(entity, new object[] { (int64)(++maxexistingcolumnvalue) });                                 break;                         }                     }                 }             }         }          idbasyncenumerator<tentity> idbasyncenumerable<tentity>.getasyncenumerator()         {             return new mockdbasyncenumerator<tentity>(data.getenumerator());         }          ienumerator<tentity> ienumerable<tentity>.getenumerator()         {             return data.getenumerator();         }          public override tentity remove(tentity entity)         {             data.remove(entity);             return entity;         }          public override ienumerable<tentity> removerange(ienumerable<tentity> entities)         {             foreach (var entity in entities)                 remove(entity);             return entities;         }          public override dbsqlquery<tentity> sqlquery(string sql, params object[] parameters)         {             throw new notsupportedexception();         }     }      internal class mockdbasyncqueryprovider<tentity> : idbasyncqueryprovider     {         internal mockdbasyncqueryprovider(iqueryprovider queryprovider)         {             queryprovider = queryprovider;         }          private iqueryprovider queryprovider { get; set; }          public iqueryable createquery(expression expression)         {             return new mockdbasyncenumerable<tentity>(expression);         }          public iqueryable<telement> createquery<telement>(expression expression)         {             return new mockdbasyncenumerable<telement>(expression);         }          public object execute(expression expression)         {             return queryprovider.execute(expression);         }          public tresult execute<tresult>(expression expression)         {             return queryprovider.execute<tresult>(expression);         }          public task<object> executeasync(expression expression, cancellationtoken cancellationtoken)         {             return task.fromresult(execute(expression));         }          public task<tresult> executeasync<tresult>(expression expression, cancellationtoken cancellationtoken)         {             return task.fromresult(execute<tresult>(expression));         }     }      internal class mockdbasyncenumerable<t> : enumerablequery<t>, idbasyncenumerable<t>, iqueryable<t>     {         public mockdbasyncenumerable(ienumerable<t> enumerable)             : base(enumerable)         {         }          public mockdbasyncenumerable(expression expression)             : base(expression)         {         }          iqueryprovider iqueryable.provider         {             { return new mockdbasyncqueryprovider<t>(this); }         }          public idbasyncenumerator<t> getasyncenumerator()         {             return new mockdbasyncenumerator<t>(this.asenumerable().getenumerator());         }          idbasyncenumerator idbasyncenumerable.getasyncenumerator()         {             return getasyncenumerator();         }     }      internal class mockdbasyncenumerator<t> : idbasyncenumerator<t>     {         public mockdbasyncenumerator(ienumerator<t> enumerator)         {             enumerator = enumerator;         }          public void dispose()         {             enumerator.dispose();         }          public t current         {             { return enumerator.current; }         }          object idbasyncenumerator.current         {             { return current; }         }          private ienumerator<t> enumerator { get; set; }          public task<bool> movenextasync(cancellationtoken cancellationtoken)         {             return task.fromresult(enumerator.movenext());         }     } } 

Comments

Popular posts from this blog

javascript - Using jquery append to add option values into a select element not working -

Android soft keyboard reverts to default keyboard on orientation change -

Rendering JButton to get the JCheckBox behavior in a JTable by using images does not update my table -