7

In Java, when I have a class that calls some other class' static method, I always encapsulate this so I can test it without actually hitting that real resource. For example:

public class HasSomeStaticCall
{
    public HasSomeStaticCall()
    {
        this.something = callStaticThing();
    }

    protected String callStaticThing()
    {
        return SomeThirdParty.getFromStaticMethod();
    {
}

In Java, I can then use Spy instead of Mock and then use all the real methods except for that one.

Example:

public void test()
{
    HasSomeStaticCall obj = Mockito.spy( HasSomeStaticCall.class );

    //Only mock this one method
    Mockito.doReturn( "SomeValue" ).when( obj ).callStaticThing();
}

How would I do this in C#? (I'm using the .Net Framework 4.7.x, not .Net Core)

Don Rhummy
  • 24,730
  • 42
  • 175
  • 330
  • You can use a library such as `Moq` or `AutoMock`, however you have to either mark the method as `virtual` or implement an interface to mock the method. In the case of using an interface, you'd mock the interface being injected into the class constructor. – ColinM Apr 11 '19 at 19:11
  • @ColinM Thank you. I'm using `Moq`, but where does it have `Spy`? – Don Rhummy Apr 11 '19 at 19:12
  • `HasSomeStaticCall obj = new Mock(); obj.Setup(p => p.callStaticThing()).Returns("SomeValue");`, assuming that `callStaticThing has the following signature` `protected virtual string callStaticThing()`. I've never used Java and Mockito so I'm not sure of how a test would be structured, but this sounds like what you're intending. – ColinM Apr 11 '19 at 19:14
  • @ColinM yes, but I want the rest of the methods to call the real code, not mocked code. Won't making it as a mock, make all methods mocked? – Don Rhummy Apr 11 '19 at 19:15
  • See the first paragraph of this answer https://stackoverflow.com/a/20402465/5062791 – ColinM Apr 11 '19 at 19:18
  • Note that default for Java is all instance methods are virtual while C# is not... So what is trivial in Java (derive and override only couple methods) becomes very complicated in C#/.Net world (unless you control classes and can make method virtual)... – Alexei Levenkov Apr 11 '19 at 19:21

1 Answers1

5

With C# mocking frameworks, you do not have a concept like a spy. What you can do is to create a mock and arrange it to call the original code where your method that calls the static method can return the value you desire. You should have in mind that the free C# mocking frameworks will work only with interfaces and virtual methods. So if your case is to arrange a public virtual method that returns a value than here is how this could be done. I will use the free version JustMock for the next examples:

HasSomeStaticCall obj = Mock.Create<HasSomeStaticCall>(Behavior.CallOriginal);
Mock.Arrange(() => obj.callStaticThing()).Returns("SomeValue");

var actual = obj.callStaticThing();

Assert.AreEqual("SomeValue", actual);

JustMock has a commercial version that allows you to mock non-public methods like the protected method in your code. Here is how the arrangement should look like for such a method:

HasSomeStaticCall obj = Mock.Create<HasSomeStaticCall>(Behavior.CallOriginal);

Mock.NonPublic.Arrange<string>(obj, "callStaticThingProtected").Returns("SomeValue");
var actual = obj.MethodThatCallsTheProtectedcallStaticThing();

Assert.AreEqual("SomeValue", actual);

Of course, there should be a way to call the protected method. This is why I have used the MethodThatCallsTheProtectedcallStaticThing. However, it is not required if you have another way of executing this method.

I have noticed that in your scenario you are actually setting the value of a field in the constructor with the result from the method that calls the static method. Most of the C# mocking frameworks will allow you three possible options to handle the constructor execution: Calling the original constructor, Not calling the constructor and do something else instead of calling the constructor. Neither of them allows you to arrange some of the instance methods of your HasSomeStaticCall class in advance before creating the mock. This is a problem as the constructor is doing stuff you would like to preserve. JustMock allows you to mock static methods. Here is an example for your scenario:

Mock.Arrange(() => SomeThirdParty.getFromStaticMethod()).Returns("SomeValue");

HasSomeStaticCall obj = new HasSomeStaticCall();
var actual = obj.Something;

Assert.AreEqual("SomeValue", actual);

I have created a Something property to access the value of the field which is not required if you have another way to verify the value when needed.

If you are interested in JustMock you could check the feature comparison table for JustMock and JustMock Lite

Disclaimer. I am one of the developers responsible for JustMock.

Mihail Vladov
  • 498
  • 4
  • 9