Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking method results

I'm trying to find a way to fake the result of a method called from within another method.

I have a "LoadData" method which calls a separate helper to get some data and then it will transform it (I'm interested in testing the transformed result).

So I have code like this:

public class MyClass(){
  public void LoadData(){
    SomeProperty = Helper.GetSomeData();
 }
 public object SomeProperty {get;set;}
}

I want to have a known result from the Helper.GetSomeData() method. Can I use a mocking framework (I've got fairly limited experience with Rhino Mocks but am open to anything) to force an expected result? If so, how?

*Edit - yeah as expected I couldn't achieve the hack I wanted, I'll have to work out a better way to set up the data.

like image 904
Aaron Powell Avatar asked Sep 18 '08 07:09

Aaron Powell


2 Answers

You have a problem there. I don't know if thats a simplified scenario of your code, but if the Helper class is used that way, then your code is not testable. First, the Helper class is used directly, so you can't replace it with a mock. Second, you're calling a static method. I don't know about C#, but in Java you can't override static methods.

You'll have to do some refactoring to be able to inject a mock object with a dummy GetSomeData() method.

In this simplified version of your code is difficult to give you a straight answer. You have some options:

  • Create an interface for the Helper class and provide a way for the client to inject the Helper implementation to the MyClass class. But if Helper is just really a utility class it doesn't make much sense.
  • Create a protected method in MyClass called getSomeData and make it only call Helper.LoadSomeData. Then replace the call to Helper.LoadSomeData in LoadData with for getSomeData. Now you can mock the getSomeData method to return the dummy value.

Beware of simply creating an interface to Helper class and inject it via method. This can expose implementation details. Why a client should provide an implementation of a utility class to call a simple operation? This will increase the complexity of MyClass clients.

like image 88
Marcio Aguiar Avatar answered Oct 16 '22 03:10

Marcio Aguiar


I would recommend converting what you have into something like this:

public class MyClass()
{
    private IHelper _helper;

    public MyClass()
    {
        //Default constructor normal code would use.
        this._helper = new Helper();
    }

    public MyClass(IHelper helper)
    {
        if(helper == null)
        {
            throw new NullException(); //I forget the exact name but you get my drift ;)
        }
        this._helper = helper;
    }

    public void LoadData()
    {
        SomeProperty = this._helper.GetSomeData();
    }
    public object SomeProperty {get;set;}
}

Now your class supports what is known as dependency injection. This allows you to inject the implementation of the helper class and it ensures that your class need only depend on the interface. When you mock this know you just create a mock that uses the IHelper interface and pass it in to the constructor and your class will use that as though it is the real Helper class.

Now if you're stuck using the Helper class as a static class then I would suggest that you use a proxy/adapter pattern and wrap the static class with another class that supports the IHelper interface (that you will also need to create).

If at some point you want to take this a step further you could completely remove the default Helper implementation from the revised class and use IoC (Inversion of Control) containers. If thiis is new to you though, I would recommend focusing first on the fundamentals of why all of this extra hassle is worth while (it is IMHO).

Your unit tests will look something like this psuedo-code:

public Amazing_Mocking_Test()
{
    //Mock object setup
    MockObject mockery = new MockObject();
    IHelper myMock = (IHelper)mockery.createMockObject<IHelper>();
    mockery.On(myMock).Expect("GetSomeData").WithNoArguments().Return(Anything);

    //The actual test
    MyClass testClass = new MyClass(myMock);
    testClass.LoadData();

    //Ensure the mock had all of it's expectations met.
    mockery.VerifyExpectations();
}

Feel free to comment if you have any questions. (By the way I have no clue if this code all works I just typed it in my browser, I'm mainly illustrating the concepts).

like image 34
Justin Bozonier Avatar answered Oct 16 '22 04:10

Justin Bozonier