4

I'm new at unit testing, and I'm trying to mock a static method in a static class. I already read that you can't do that, but I was looking a way to work around that.

I can't modify the code, and making the same function without being static is not an option because they check the code coverage of the test, and I need at least 90%.
I already tried to mock the variables that it uses but it doesn't work.

public static class MyClass
{
    public static response MyMethod(HttpSessionStateBase Session, 
        otherVariable, stringVariable)
    {
        //some code
    }
}

public ActionResult MyClassTested()
{
    var response = MyClass.MyMethod(Session);
    //more code
}

My problem is that this method is inside a controller that declares a var with the response, and according to that redirects the user.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292

2 Answers2

1

If you can't modify the code then I don't think it is possible to work around this using DynamicProxy-based libraries like NSubstitute. These libraries use inheritance to intercept members on classes, which is not possible for static and non-virtual members.

I suggest trying Fakes. One of the examples on that page covers stubbing DateTime.Now.

Other alternatives that can mock static members include TypeMock and Telerik JustMock.

Related question: https://stackoverflow.com/q/5864076/906

David Tchepak
  • 9,826
  • 2
  • 56
  • 68
  • Yes, i also read that, but i'm using VS 2017 the professional version, so i don't have fakes, but it appers that i won't be able to do it, that i have to use something else or modify the code – Ricardo Sanchez Santos Jun 17 '19 at 20:10
  • @RicardoSanchezSantos You could try TypeMock or Telerik JustMock. I have updated the answer to mention these. Most .NET mocking libraries intercept calls on classes via inheritance as described [here](https://nsubstitute.github.io/help/how-nsub-works/), so you'll need to pick one of these other libraries that work via the profiling API or similar instead. – David Tchepak Jun 18 '19 at 00:34
  • is there something like typemock or telerik free? – Ricardo Sanchez Santos Jun 20 '19 at 18:22
  • I tried to install Pose, but i have a problem with the framework = 4.6.2 wich isn't compatible with Pose, also i tried Smock, but i'm not pretty sure on how to use it, and i'm investigating about moles of microsoft – Ricardo Sanchez Santos Jun 20 '19 at 21:20
  • I'm not sure about pricing sorry. It may be best asking about Pose and Smock on their project sites and maybe other SO questions about the specific problems you're having with them. Best of luck! – David Tchepak Jun 20 '19 at 22:29
1

There could be a nicer solution to this sort of problem... depending on what you can get away with.

I recently ran into this myself after having written a static utility class used to, essentially, create various truncations of the Guid format. While writing an integration test, I realized that I needed to control a random Id that was being generated from this utility class so that I could deliberately issue this Id to the API and then assert on the result.

The solution I went with at the time was to provide the implementation from a static class, but call that implementation from within a non-static class (wrapping the static method call), which I could register and inject in the DI container. This non-static class would be the main workhorse, but the static implementation would be available in instances where I needed to call these methods from another static method (for example, I had written a lot of my integration setup code as extensions on IWevApplicationFactory, and used the static utility to create database names).

In code, e.g.

// my static implementation - only use this within other static methods when necessary. Avoid as much as possible.
public static class StaticGuidUtilities 
{
    public static string CreateShortenedGuid([Range(1, 4)] int take)
    {
        var useNumParts = (take > 4) ? 4 : take;
        var ids = Guid.NewGuid().ToString().Split('-').Take(useNumParts).ToList();
        return string.Join('-', ids);
    }
}


// Register this abstraction in the DI container and use it as the default guid utility class
public interface IGuidUtilities
{
    string CreateShortenedGuid([Range(1, 4)] int take);
}

// Non-static implementation
public class GuidUtitlities : IGuidUtilities
{
    public string CreateShortenedGuid([Range(1, 4)] int take)
    {
        return StaticGuidUtilities.CreateShortenedGuid(take);
    }
}

----

// In the tests, I can use NSubstitute...
// (Doesn't coding to the abstraction make our lives so much easier?)
var guidUtility = Substitute.For<IGuidUtilities>();
var myTestId = "test-123";
guidUtility.CreateShortenedGuid(1).Returns(myTestId);

// Execute code and assert on 'myTestId' 
// This method will call the injected non-static utilty class and return the id
var result = subjectUndertest.MethodUnderTest();

// Shouldly syntax
result.Id.ShouldBe(myTestId);
PaulG
  • 3,260
  • 1
  • 15
  • 13