c# - Proving my contracts are validating the right thing -


i have interface so:

[contractclass(typeof(contractstockdataprovider))] public interface istockdataprovider {     /// <summary>     /// collect stock data cache/ persistence layer/ api     /// </summary>     /// <param name="symbol"></param>     /// <returns></returns>     task<stock> getstockasync(string symbol);      /// <summary>     /// reset stock history values specified date     /// </summary>     /// <param name="date"></param>     /// <returns></returns>     task updatestockvaluesasync(datetime date);      /// <summary>     /// updates stock prices latest values in stockhistories table.     /// </summary>     /// <returns></returns>     task updatestockpricesasync();      /// <summary>     /// determines last population date stockhistories table, ,      /// updates table available after that.     /// </summary>     /// <returns></returns>     task bringstockhistorycurrentasync();      event action<stockeventargs> onfeedcomplete;     event action<stockeventargs> onfeederror; } 

i have corresponding contract class so:

[contractclassfor(typeof (istockdataprovider))] public abstract class contractstockdataprovider : istockdataprovider {     public event action<stockeventargs> onfeedcomplete;     public event action<stockeventargs> onfeederror;      public task bringstockhistorycurrentasync()     {         return default(task);     }      public task<stock> getstockasync(string symbol)     {         contract.requires<argumentexception>(!string.isnullorwhitespace(symbol), "symbol required.");         contract.requires<argumentexception>(symbol.equals(symbol.toupperinvariant(), stringcomparison.invariantculture),             "symbol must in uppercase.");         return default(task<stock>);     }      public task updatestockpricesasync()     {         return default(task);     }      public task updatestockvaluesasync(datetime date)     {         contract.requires<argumentoutofrangeexception>(date <= datetime.today, "date cannot in future.");         return default(task);     } } 

i made unit test so:

[testclass] public class stockdataprovidertests {     private mock<istockdataprovider> _stockdataprovider;      [testinitialize]     public void initialize()     {         _stockdataprovider = new mock<istockdataprovider>();     }      [testmethod]     [expectedexception(typeof(argumentexception))]     public async task getstockasyncsymbolemptythrowsargumentexception()      {         //arrange         var provider = _stockdataprovider.object;          //act         await provider.getstockasync(string.empty);          //assert         assert.fail("should have thrown argumentexception");     } } 

from i've read, should sufficient pass unit test, upon acting, unit test fails not throwing exception.

i'm not trying test contract functionality, interested in testing validation logic make sure requirements met concrete implementations of istockdataprovider interface.

am doing wrong? how can verify, using unit tests, have specified inputs?

update

so, while mocking interface , testing validation logic not seem work, concrete class (not inheriting abstract) validates inputs in testing. may not supported in mocking, though don't quite know why.

the reason why mocks weren't throwing exceptions quite simple. interfaces can't have methods. therefore, can't specify contracts on interface directly. but, knew this. that's why created contract class interface (which, way, should private abstract class).

because you're attempting mock interface, mocking tool knows nothing contracts. mocking tools @ definition of interface , create proxy object. proxy stand-in, double, , has no behavior @ all! now, libraries moq, can make proxies have behavior using methods such returns(it.is.any()). again, turning proxy more stub @ point. moreover, , more importantly, wouldn't work mocking libraries 1 reason: proxy created on fly, @ runtime during test. no "rewriting" of proxy being performed ccrewrite.

so how test specified right conditions contracts?

you should create new library called myprojectname.tests.stubs, example. then, should create actual stub object instance interface in project. doesn't have elaborate. enough allow call methods in unit test test contracts work expected. oh, , 1 more important thing work: enable perform runtime contract checking on newly created stubs project debug build. otherwise, stubs create inherit interface not instrumented contracts.

reference new myprojectname.tests.stubs assembly in unit test project. use stubs test interfaces. here's code (note, i'm using code post--so if contracts don't work expected, don't blame me--fix code ;) ):

// main library project //////////////////////////////////////////////////////////////////////  [contractclass(typeof(contractstockdataprovider))] public interface istockdataprovider {     /// <summary>     /// collect stock data cache/ persistence layer/ api     /// </summary>     /// <param name="symbol"></param>     /// <returns></returns>     task<stock> getstockasync(string symbol);      /// <summary>     /// reset stock history values specified date     /// </summary>     /// <param name="date"></param>     /// <returns></returns>     task updatestockvaluesasync(datetime date);      /// <summary>     /// updates stock prices latest values in stockhistories table.     /// </summary>     /// <returns></returns>     task updatestockpricesasync();      /// <summary>     /// determines last population date stockhistories table, ,      /// updates table available after that.     /// </summary>     /// <returns></returns>     task bringstockhistorycurrentasync();      event action<stockeventargs> onfeedcomplete;     event action<stockeventargs> onfeederror; }  // contract classes should: //    1. private abstract classes //    2. have method implementations //       'throw new notimplementedexception()' after contracts // [contractclassfor(typeof (istockdataprovider))] private abstract class contractstockdataprovider : istockdataprovider {     public event action<stockeventargs> onfeedcomplete;     public event action<stockeventargs> onfeederror;      public task bringstockhistorycurrentasync()     {         // if method doesn't mutate state in class,         // consider marking [pure] attribute.          //return default(task);         throw new notimplementedexception();     }      public task<stock> getstockasync(string symbol)     {         contract.requires<argumentexception>(             !string.isnullorwhitespace(symbol),             "symbol required.");         contract.requires<argumentexception>(             symbol.equals(symbol.toupperinvariant(),                  stringcomparison.invariantculture),             "symbol must in uppercase.");          //return default(task<stock>);         throw new notimplementedexception();     }      public task updatestockpricesasync()     {         // if method doesn't mutate state within         // class, consider marking [pure].          //return default(task);         throw new notimplementedexception();     }      public task updatestockvaluesasync(datetime date)     {         contract.requires<argumentoutofrangeexception>(date <= datetime.today,              "date cannot in future.");          //return default(task);         throw new notimplementedexception();     } }  // new stubs project ///////////////////////////////////////////////////////////////// using yournamespacewithinterface;  // make things simpler, use same namespace interface, // put '.stubs' on end of it. namespace yournamespacewithinterface.stubs {     // again, stub--it doesn't have     // useful. so, if you're not going use stub     // checking logic , use contract condition     // checking, it's ok return null--as you're not     // depending on return values of methods (unless     // have contract.ensures(bool condition) on methods--     // in case, matter).     public class stockdataproviderstub : istockdataprovider     {         public task bringstockhistorycurrentasync()         {             return null;         }          public task<stock> getstockasync(string symbol)         {             contract.requires<argumentexception>(                 !string.isnullorwhitespace(symbol),                 "symbol required.");             contract.requires<argumentexception>(                 symbol.equals(symbol.toupperinvariant(),                      stringcomparison.invariantculture),                 "symbol must in uppercase.");              return null;         }          public task updatestockpricesasync()         {             return null;         }          public task updatestockvaluesasync(datetime date)         {             contract.requires<argumentoutofrangeexception>(                 date <= datetime.today,                  "date cannot in future.");              return null;         }     } }  // in unit test project ////////////////////////////////////////////////////////////////// using yournamespacewithinteface.stubs  [testclass] public class stockdataprovidertests {     private istockdataprovider _stockdataprovider;      [testinitialize]     public void initialize()     {         _stockdataprovider = new stockdataproviderstub();     }      [testmethod]     [expectedexception(typeof(argumentexception))]     public async task getstockasyncsymbolemptythrowsargumentexception()      {         //act         await provider.getstockasync(string.empty);          //assert         assert.fail("should have thrown argumentexception");     } } 

by creating project containing stubs implementations of interface , enabling perform runtime contract checking on stub project, can test contract conditions in unit tests.

i highly recommend reading on unit testing , roles of various test doubles. @ 1 time, thought aren't mocks, stubs, fakes same thing. well, yes, , no. answer bit nuanced. , unfortunately, libraries moq, while great!, don't because tend muddy waters you're using in tests when using these libraries. again, that's not they're not helpful, useful, or great—but need understand you're using when you're using these libraries. recommendation can make xunit test patterns. there's website: http://xunitpatterns.com/.


Comments

Popular posts from this blog

c++ - llvm function pass ReplaceInstWithInst malloc -

Cross-Compiling Linux Kernel for Raspberry Pi - ${CCPREFIX}gcc -v does not work -

java.lang.NoClassDefFoundError When Creating New Android Project -