unit testing - How to use Moq to Prove that the Method under test Calls another Method -


i working on unit test of instance method. method happens asp.net mvc 4 controller action, don't think matters much. found bug in method, , i'd use tdd fix bug , make sure doesn't come back.

the method under test calls service returns object. calls internal method passing string property of object. bug under circumstances, service returns null, causing method under test throw nullreferenceexception.

the controller uses dependency injection, have been able mock service client have return null object. problem want change method under test when service returns null, internal method should called default string value.

the way think use mock class under test. want able assert, or verify internal method has been called correct default value. when try this, mockexception stating invocation not performed on mock. yet able debug code , see internal method being called, correct parameters.

what's right way prove method under test calls method passing particular parameter value?

i think there's code smell here. first question i'll ask myself in such situation is, "internal" method internal/ private controller under test. controller's responsibility "internal" task? should controller change when internal method's implementation changes? may not.

in case, pull out new targeted class, has public method stuff until internal controller. refactoring in place, use callback mechanism of moq , assert argument value.

so eventually, end mocking 2 dependancies: 1. external service 2. new targeted class has controller's internal implementation

now controller isolated , can unit tested independently. also, "internal" implementation becomes unit testable , should have own set of unit tests too.

so code , test this:

public class controllerundertest {      private iexternalservice service { get; set; }     private newfocusedclass newfocusedclass { get; set; }     const string defaultvalue = "defaultvalue";      public controllerundertest(iexternalservice service, newfocusedclass newfocusedclass)     {         service = service;         newfocusedclass = newfocusedclass;     }      public void methodundertest()     {         var returnedvalue = service.externalmethod();         string valuetobepassed;         if (returnedvalue == null)         {             valuetobepassed = defaultvalue;         }         else         {             valuetobepassed = returnedvalue.stringproperty;         }         newfocusedclass.focusedbehvaior(valuetobepassed);     } }  public interface iexternalservice {     returnclass externalmethod(); }  public class newfocusedclass {     public virtual void focusedbehvaior(string param)     {      } }  public class returnclass {     public string stringproperty { get; set; } }  [testclass] public class controllertests {     [testmethod]     public void testmethod()     {         //given         var mockservice = new mock<iexternalservice>();         mockservice.setup(s => s.externalmethod()).returns((returnclass)null);         var mockfocusedclass = new mock<newfocusedclass>();         var actualparam = string.empty;         mockfocusedclass.setup(x => x.focusedbehvaior(it.isany<string>())).callback<string>(param => actualparam = param);          //when         var controller = new controllerundertest(mockservice.object, mockfocusedclass.object);         controller.methodundertest();          //then         assert.areequal("defaultvalue", actualparam);     } } 

edit: based on suggestion in comments use "verify" instead of callback. easier way verify parameter value using strict moq behavior , verify call on mock after system under test executed. modified test below:

[testmethod]     public void testmethod()     {         //given         var mockservice = new mock<iexternalservice>();         mockservice.setup(s => s.externalmethod()).returns((returnclass)null);         var mockfocusedclass = new mock<newfocusedclass>(mockbehavior.strict);         mockfocusedclass.setup(x => x.focusedbehvaior(it.is<string>(s => s == "defaultvalue")));          //when         var controller = new controllerundertest(mockservice.object, mockfocusedclass.object);         controller.methodundertest();          //then         mockfocusedclass.verify();     } 

Comments

Popular posts from this blog

c++ - QTextObjectInterface with Qml TextEdit (QQuickTextEdit) -

javascript - angular ng-required radio button not toggling required off in firefox 33, OK in chrome -

xcode - Swift Playground - Files are not readable -