Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I mock this static method

Tags:

c#

moq

I have this code:

public static bool IsValidVoucher(string id)
{
    //read tsv files
    var temp1 = AppData.GetAppData("stringval");            
    // code that need to be tested        
    return true;        
}

And I like to create unit test, but how can I mock AppData.GetAppData("stringval") to whatever I want the value is, so I can test the rest of code.

The AppData class is:

public class AppData
{
    public static object GetAppData(string name)
    {
        //...
    }
}
like image 598
Mr.Rendezvous Avatar asked Aug 07 '15 07:08

Mr.Rendezvous


People also ask

Can we mock static variable?

Mocking Static Classes, Methods, and Properties Overview The difference between the two classes is that a static class cannot be instantiated. The new operator cannot create a variable of the class type. Because there is no instance variable, the class name itself should be used to access the members of a static class.

Can I mock a method?

mock() method with Answer: It is used to create mock objects of a class or interface with a specific procedure. It is an advanced mock method, which can be used when working with legacy systems. It takes Answer as a parameter along with the class or interface name.


2 Answers

Static methods cannot be mocked in an easy way. You basically have two choices:

  1. If you own the AppData class, change the implementation to implement an interface (e.g. IAppData) and remove the static modifier on the GetAppData method so you can mock it.

    public interface IAppData
    {
        object GetAppData(string id);
    }
    
    public class AppData : IAppData
    {
        public object GetAppData(string id) {}
    }
    
    public class Foo
    {
        private readonly IAppData _appData;
    
        public Foo(IAppData appData)
        {
            _appData = appData;
        }
    
        public bool IsValidVoucher(string id)
        {
            // Call through object instance instead for class reference
            var temp1 = _appData.GetAppData("stringval");
        }
    }
    
  2. If you do not own the AppData class, use a wrapper class (e.g. AppDataWrapper) that implements an interface and call that method from IsValidVoucher instead:

    public interface IAppData
    {
        object GetAppData(string id);
    }
    
    public class AppDataWrapper : IAppData
    {
        public object GetAppData(string id)
        {
            return AppData.GetAppData(id);
        }
    }
    
    public class Foo
    {
        private readonly IAppData _appData;
    
        public Foo(IAppData appData)
        {
            _appData = appData;
        }
    
        public bool IsValidVoucher(string id)
        {
            var temp1 = _appData.GetAppData("stringval");
        }
    }
    

You can then unit test Foo using Moq (using xunit as an example here):

public class FooTests
{
    private readonly IAppData _mockAppData;

    public FooTests()
    {
        var mockAppData = new Mock<IAppData>();
        mockAppData.Setup(m => m.GetAppData(It.IsAny<string>)).Returns("my test value");
        _mockAppData = mockAppData.Object;
    }

    [Fact]
    public void IsValidVoucher_ValidAppData_Returns()
    {
        var foo = new Foo(_mockAppData);
        // Unit test foo.IsValidVoucher
    }
}
like image 168
rexcfnghk Avatar answered Oct 13 '22 20:10

rexcfnghk


Well, I think everyone's comments so far is technically correct - using something like RhinoMocks or Moq, you really can't mock static methods in a facile, straightforward manner.

But using Moles, you definitely can. So if you have significant (currently) untestable code that reside within static methods, I think you should be looking into Moles.

(This link is a bit dated but I still find it helpful) http://research.microsoft.com/en-us/projects/pex/molesmanual.pdf

(Key text)

Moles can be used to detour any .NET method, including non-virtual and static methods in sealed types.

How it works: Suppose you have a typical situation like this:

public static class SomeStaticClass
{
    public static int SomeStaticMethod(string s)
    {
        return "Static method called: " + s;
    }
}

public class SomeInstanceClass
{
    public string SomeInstanceMethod(string s)
    {
        return SomeStaticClass.SomeStaticMethod(s);
    }
}

Using Moles, your test code would look like this:

[TestMethod()]
[HostType("Moles")]
public void ShouldBeAbleToTestStaticMethod()
{
    var instance = new SomeInstanceClass();
    var testValue = instance.SomeInstanceMethod("Some test string");
    SomeStaticClass.SomeStaticMethod = (s) => "Moled you! " + s;
    Assert.That(testValue, Is.EqualTo("Moled you! Some test string"); // sorry, this has code smell, lol
}

Of course you need to set up Moles into your test project, so be sure to look it up - lots of web resources to help you on your way.

Some helpful posts:

https://msdn.microsoft.com/en-us/library/ff798308.aspx

http://adventuresdotnet.blogspot.com/2011/03/mocking-static-methods-for-unit-testing.html

https://wannabeegeek.wordpress.com/2013/03/13/unit-testing-made-easy-with-moles-part-i/

like image 1
code4life Avatar answered Oct 13 '22 20:10

code4life