2

In justmock we can return mocked instances instead of actual instances by Arranging the constructor call like

Mock.Arragne(()=>new MyClass(Arg.IsAny<string>())).IgnoreInstance().Returns(Mock.Create<MyClass>());

but when I tried the same with UrlHelper class, instead of mocked type, actual type is getting instantiated. Can anybody tell if there's any mistake in this:

UrlModel class

    public class UrlModel
    {
        private UrlHelper url;
        public UrlModel()
        {
           url = new UrlHelper(HttpContext.Current.Request.RequestContext);
        }
    }

Test method :

public void UrlTest()
{
   Mock.Arrange(() => HttpContext.Current.Request.RequestContext).Returns(Mock.Create<RequestContext>());

    var mockedUrl = Mock.Create<UrlHelper>();

    Mock.Arrange(() => new UrlHelper(Arg.IsAny<RequestContext>()))
        .IgnoreArguments()
        .IgnoreInstance()
        .Returns(mockedUrl);

    //Here url will have actual instance instead of mocked instance
    var model = new UrlModel();

    //Assert is ommitted for bravity .. 
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
Necromancer
  • 194
  • 3
  • 13

3 Answers3

1

You can use Typemock to test your code without adding any new interfaces, by faking RequestContext and modifying the property behavior:

[TestMethod,Isolated]
public void UrlTest()
{
    //Arrange 
    var fakeRequest = Isolate.Fake.Instance<RequestContext>();
    Isolate.WhenCalled(() => HttpContext.Current.Request.RequestContext).WillReturn(fakeRequest);

    //Act
    var res = new UrlModel();
    //getting the private field so it can be asserted
    var privateField = Isolate.NonPublic.InstanceField(res, "url").Value as UrlHelper;

    //Assert
    Assert.AreEqual(fakeRequest, privateField.RequestContext);
}
JamesR
  • 745
  • 4
  • 15
0

You are manually instantiating an instance of UrlHelper in the constructor of UrlModel. UrlModel is now tightly coupled to UrlHelper (new is glue). Make an dependency abstraction that you can allow for a more loosely coupled model and improved mock-ability

public interface IUrlHelperAccessor {
    UrlHelper UrlHelper { get; }
}

and inject that into the UrlModel

public class UrlModel {
    private UrlHelper url;
    public UrlModel(IUrlHelperAccessor accessor) {
       url = accessor.UrlHelper;
    }
    //...other code
}

Now you arrange the test accordingly

public void UrlTest() {
    Mock.Arrange(() => HttpContext.Current.Request.RequestContext)
        .Returns(Mock.Create<RequestContext>());

    var mockedUrl = Mock.Create<UrlHelper>(Constructor.Mock);
    var mockedAccessor = Mock.Create<IUrlHelperAccessor>();

    Mock.Arrange(() => mockedAccessor.UrlHelper).Returns(mockedUrl);

    //Here url will have actual instance instead of mocked instance
    var model = new UrlModel(mockedAccessor);

    //Assert is omitted for brevity .. 

}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
0

The only reason why the constructor mocking in this case would not have worked is that the UrlModel class has been part of a test class - code in test classes is not itself mockable.

The other thing that comes to mind is that you might have been misled by the debugger. When you create a mock of a non-abstract type with the profiler running, the instance itself is of the same type as the mocked type - it's not a derived type, say, UrlHelperMock, as is the case when the profiler is not running. Can you confirm using the debuggers Make Object ID function that the mock instance and the instance returned from new are really not the same?

Did you come to the conclusion that the new expression mocking did not work, because your arrangements of UrlHelper did not work, or was it something else?

Stefan Dragnev
  • 14,143
  • 6
  • 48
  • 52