Mocking a Base Class Property

7 posts, 0 answers
  1. Kalyan
    Kalyan avatar
    4 posts
    Member since:
    Feb 2017

    Posted 13 Feb Link to this post

    Hello,

    I'm new to JustMock and have been playing with it only for a few hours.  I have been able to convert a few of my existing tests from Microsoft Fakes to JustMock.  However, there's one test, where I'm having a lot of trouble and I'm hoping someone can help me with it.

     

    I have a class that derives from the System.Web.Http.ApiController and here is a snapshot of it:

    public class MyApiController : ApiController {
        public HttpResponseMessage Post(EPAQuestionsetLookupRequest lookup) {
            try {
                if (!ModelState.IsValid) {
                    return new HttpResponseMessage(HttpStatusCode.NotAcceptable);
                }
                return new HttpResponseMessage(HttpStatusCode.OK);
            } catch {
                return new HttpResponseMessage(HttpStatusCode.InternalServerError);
            }
        }
    }

     

    I have a test written as the follows:

    [TestMethod]
    public void PostNotValidState() {
        var controller = Mock.Create<MyApiController>();
        Mock.Arrange(() => controller.ModelState.IsValid).Returns(false).MustBeCalled();
        // Mock.Arrange(() => ((ApiController)controller).ModelState.IsValid).Returns(false).MustBeCalled();
        var response = controller.Post(lookup);
     
        Assert.AreEqual(HttpStatusCode.NotAcceptable, response.StatusCode);
        Mock.Assert(controller);
    }

     

    I've tried it in the above way and also using a Container instead.  But, in both cases, it seems like the ModelState.IsValid is continuing to return true (or the method during the test, is actually not using the arrangement I have, which is confirmed by the fact that the Mock.Assert is failing on the MustBeCalled) and is failing my test.  What's the best way for me to be able to mock the ModelState.IsValid to return false and for it to be honored?

  2. Svetlozar
    Admin
    Svetlozar avatar
    294 posts

    Posted 16 Feb Link to this post

    Hello,

    Thank you for your great question. Mocks have behaviors. If you don't specify the behavior when you create the mock the default is RecursiveLoose which creates empty implementations for all members in the mocked instance. It is quite handy if you want to replace implementations, because you cut ties with all dependencies. What happens here is that you don't call your Post method, but the mocked Post method, which returns the default value.

    When you want to call the original implementation you have to set the behavior to CallOriginal.

    Here is the sample

    [TestMethod]
    public void TestMethod1()
    {
        var controller = Mock.Create<MyApiController>(Behavior.CallOriginal);
        Mock.Arrange(() => controller.ModelState.IsValid).Returns(false).MustBeCalled();
        var lookup = new EPAQuestionsetLookupRequest();
        var response = controller.Post(lookup);
     
        Assert.AreEqual(HttpStatusCode.NotAcceptable, response.StatusCode);
        Mock.Assert(controller);
    }

    I hope that helps. Let me know if you have any questions. 

    Regards,
    Svetlozar
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  3. Kalyan
    Kalyan avatar
    4 posts
    Member since:
    Feb 2017

    Posted 16 Feb in reply to Svetlozar Link to this post

    Thank you very much.  That did it.

    After that worked, I was trying the same kind of test using the Mocking Container and I still see it not mocking the response on the IsValid call.  Here is my code:

     

    var container = new MockingContainer<MyApiController>(new AutoMockSettings { MockBehavior = Behavior.CallOriginal });
     
    container.Arrange<System.Web.Http.ModelBinding.ModelStateDictionary>(ModelState => ModelState.IsValid).Returns(false).MustBeCalled();
    var response = container.Instance.Post(lookup);
    Assert.AreEqual(HttpStatusCode.NotAcceptable, response.StatusCode);
    container.Assert();

     

    Greatly appreciate, if you can point out what I'm messing up here.

     

    Thanks,

    Kalyan

  4. Kalyan
    Kalyan avatar
    4 posts
    Member since:
    Feb 2017

    Posted 16 Feb in reply to Svetlozar Link to this post

    This definitely seems to work.  But, I'm still a little confused.  Without the CallOriginal behavior, when I debug, it still takes me into the implementation of my Post method and I'm able to step through the code.  So, if it is not using the original implementation, why is it stepping through my implementation?  I'm definitely confused.

     

    Thanks,

    Kalyan

  5. Svetlozar
    Admin
    Svetlozar avatar
    294 posts

    Posted 21 Feb Link to this post

    Hello,

    I am really sorry for the misunderstanding. The debugger follows the information from the pdb file. That is the file that has the source code -> IL map that is used for debugging. Since we rewrite the IL code at runtime we also try to rewrite the pdb stream to point to the generated code, but there are still some cases where we fall short to do so. I hope that makes sense. 

    Regards,
    Svetlozar
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  6. Kalyan
    Kalyan avatar
    4 posts
    Member since:
    Feb 2017

    Posted 21 Feb in reply to Svetlozar Link to this post

    OK.  I understand.  Will appreciate if you can help me understand what's going on with the way I'm using the Mocking Container to solve this exact scenario.  The post is in one of the comments above: http://www.telerik.com/forums/mocking-a-base-class-property#6UyLeSO4WUeZU0Wt3IafdQ

     

    Thanks,

    Kalyan

  7. Svetlozar
    Admin
    Svetlozar avatar
    294 posts

    Posted 23 Feb Link to this post

    Hi,

    I am sorry for the misunderstanding. 

    Automocking works with Ninject under the hood. You can't mock arbitrary properties with it. I suggest you continue with the standard way of mocking your dependencies. 

    Regards,
    Svetlozar
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Back to Top