MOQ unit Testing for C# .NET basic CRUD Controller Routing -
i trying set basic moq testing crud routes controller. our application small , want establish basic testing first before move more advance testing (using fakes , not).
this current test page:
[testclass()] public class adminnotestest { [testmethod] public void creatingonenote() { var request = new mock<httprequestbase>(); request.setup(r => r.httpmethod).returns("post"); var mockhttpcontext = new mock<httpcontextbase>(); mockhttpcontext.setup(c => c.request).returns(request.object); var controllercontext = new controllercontext(mockhttpcontext.object, new routedata(), new mock<controllerbase>().object); var adminnotecontroller = new adminnotescontroller(); adminnotecontroller.controllercontext = controllercontext; var result = adminnotecontroller.create("89df3f2a-0c65-4552-906a-08bceabb1198"); assert.isnotnull(result); } [testmethod] public void deletingnote() { var controller = new adminnotescontroller(); } } }
here able see controller method trying hit , create note.
[httppost] [validateantiforgerytoken] public actionresult create(adminnote adminnote) { try { if (modelstate.isvalid) { adminnote.adminkey = system.web.httpcontext.current.user.identity.getuserid(); adminnote.adminname = system.web.httpcontext.current.user.identity.getusername(); adminnote.createdate = datetime.now; adminnote.modifieddate = datetime.now; adminnote.objectstate = objectstate.added; _adminnoteservice.insert(adminnote); return redirecttoaction("userdetails", "admin", new { userkey = adminnote.userkey }); } } catch (exception ex) { controllerconstants.handleexception(ex); viewbag.popupmessage(string.format("we're sorry error occurred. {0}", ex.message)); } return view(adminnote); }
i know in order create method work need provide method adminkey , adminname. dont want hit database of these tests , have read possible dont have lot of experience , wondering if guide me in process best way approach , provide info.
thanks guys , hope after question can better @ unit testing.
i believe trying achieve direction on writing unit test around create action. , don't want hit database. want simple , don't want use advanced fakes.
there few tests may write here. below scenarios may want think. a. whether adminservice.insert method on adminnoteservice called.
b. whether adminservice.insert method called expected parameters
c. redirecttoaction method return expected type of result.
d. when exception being thrown whether exeception has been thrown correct message, exception type etc.
e. verify calls when model state valid.
there few tests can write, below example started.
first thing clear on trying unit test. way express in test method name. let's want target 'c'
instead of test method "creatingonenote" prefer test method name below..
public void createaction_modelstateisvalid_ensureredirecttoactioncontainsexpectedresult()
i make following changes sut/controller (system under test)
public class adminsnotescontroller : controller { private readonly iadminnoteservice _adminnoteservice; public adminsnotescontroller(iadminnoteservice adminnoteservice) { _adminnoteservice = adminnoteservice; fakedatetimedelegate = () => datetime.now; } public func<datetime> datetimedelegate { get; set; } [httppost] [validateantiforgerytoken] public actionresult create(adminnote adminnote) { try { if (modelstate.isvalid) { adminnote.adminkey = this.controllercontext.httpcontext .user.identity.getuserid(); adminnote.adminname = this.controllercontext.httpcontext .user.identity.getusername(); adminnote.createdate = datetimedelegate(); adminnote.modifieddate = datetimedelegate(); adminnote.objectstate = objectstate.added; _adminnoteservice.insert(adminnote); return redirecttoaction("userdetails", "admin", new { userkey = adminnote.userkey }); } } catch (exception ex) { controllerconstants.handleexception(ex); viewbag.popupmessage(string.format ("we're sorry error occurred. {0}", ex.message)); } return view(adminnote); } }
as have noticed a. don't use real system date time, instead use datetime delegate. allows me provide fake date time during testing. in real production code use real system date time.
b. instead of useing httpcontext.current.. can use controllercontext.httpcontext.user.identity. allow stub our httpconext , controllercontext user , identity. please see test below.
[testclass] public class adminnotescontrollertests { [testmethod] public void createaction_modelstateisvalid_ensureredirecttoactioncontainsexpectedroutes() { // arrange var fakenote = new adminnote(); var stubservice = new mock<iadminnoteservice>(); var sut = new adminsnotescontroller(stubservice.object); var fakehttpcontext = new mock<httpcontextbase>(); var fakeidentity = new genericidentity("user"); var principal = new genericprincipal(fakeidentity, null); fakehttpcontext.setup(t => t.user).returns(principal); var controllercontext = new mock<controllercontext>(); controllercontext.setup(t => t.httpcontext) .returns(fakehttpcontext.object); sut.controllercontext = controllercontext.object; sut.fakedatetimedelegate = () => new datetime(2015, 01, 01); // act var result = sut.create(fakenote) redirecttorouteresult; // assert assert.areequal(result.routevalues["controller"], "admin"); assert.areequal(result.routevalues["action"], "userdetails"); } }
this test can simplify lot if familiar advanced unit testing concepts such automocking. time being, i'm sure point right direction.
Comments
Post a Comment