7
public static void Mock(out IProgram prog, out IJson json)
{    
    prog = Substitute.For<IProgram>();
    IJson = Substitute.For<IJson>();

    prog.SaveProg(1, 1, 1, "Somthing", 1, DateTime.UtcNow,
                 (DateTime.UtcNow + TimeSpan.FromDays(10)), 
                 10, "someemail@email.com", DateTime.UtcNow, 1)
        .Returns(ObjectResult<int?>); 
}

I'm getting an error when calling Returns(ObjectResult<int?>) because ObjectResult is protected class. How can I work around this to be able to call my mocked method from the actual method?

Michael Flanakin
  • 472
  • 1
  • 5
  • 18
Karlen M
  • 101
  • 2
  • 5
  • Thanks Arturo for edit – Karlen M Feb 17 '16 at 22:27
  • 2
    The problem with made up examples is that if you don't check them, they are worse than meaningless. There are many issues with your question that you may wish to address. The code example you've given wouldn't compile. `.Returns` expects an instance, not a type. You're currently mocking interfaces, which can't have protected methods. `ObjectResult` isn't a protected class (a class needs to be nested in order to be protected). There are different versions of ObjectResult, some of which are sealed, some of which have protected constructors. Which version are you trying to work with? – forsvarir Feb 20 '16 at 15:43
  • 1
    Why do you care what the result is of a class you can't see? Can you test in a way which acts off of the result of ObjectResult so you don't have to touch the class? – Timothy Gonzalez Aug 31 '17 at 17:20

2 Answers2

9

NSubstitute overrides the behavior of a method of a substitute after you have invoked that method, but it actually does not care how you have invoked that method. This allows you to call it via reflection.

Below is a very detailed example:

public class SomeRepository
{
    public string ReadData() => ActuallyPerformDataReading();
    protected virtual string ActuallyPerformDataReading() => "some wrong data";
}

public class SomeClass
{
    SomeRepository _someRepository;
    public SomeClass(SomeRepository someRepository)
    {
        _someRepository = someRepository;
    }

    public string ReadSomething() => _someRepository.ReadData();
}


var repositorySub = Substitute.For<SomeRepository>();
repositorySub.GetType().GetMethod("ActuallyPerformDataReading", BindingFlags.NonPublic | BindingFlags.Instance)
    .Invoke(repositorySub, new object[] {}).Returns("some test data");
var sut = new SomeClass(repositorySub);

var result = sut.ReadSomething(); //"some test data"
meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
  • Thanks for this straightforward solution. It's best to be able to test code in a way that can be considered hackish than to not test at all (when you can't change the code in question)! – Jean-Sébastien Tremblay Jun 19 '20 at 17:44
-4

You shouldn't be able to mock a protected class/method. It's protected explicitly so you can't do that. If you need to mock it, make it public. If it's someone else's method and you think you need to mock it, you're probably testing incorrectly.

Edit: Any functionality in a protected method can only be used by a public method in that same class. Mock that public method to act however you want given some desired result from the protected method.

Necoras
  • 6,743
  • 3
  • 24
  • 45
  • 3
    I cant change access modifier. What's you advice besides what I know already? – Karlen M Feb 17 '16 at 22:23
  • 2
    Methods are unlikely to be marked as protected to explicitly prevent mocking / prevent creation of test doubles. In some instances such as `ObjectResult` protected constructors are added specifically to facilitate the creation of test doubles. https://msdn.microsoft.com/en-us/library/mt154818(v=vs.113).aspx#M:System.Data.Entity.Core.Objects.ObjectResult`1. – forsvarir Feb 20 '16 at 15:52
  • If you aren't supposed to mock protected methods, then why have `private` and `protected`? This is really a limitation of the testing framework, because I can extend the class and mock out the protected method. It should have `virtual` if it really was intended to be changed, but I can still mock it. Doing all of that to create a test double results in very heavy code that I expect a mocking framework to reduce. – Timothy Gonzalez Aug 31 '17 at 17:14
  • We can inherit from the class in your test project and export method/properties as public which can internally get/set/access the protected member ? – Brij Sep 10 '19 at 09:57