3

I know a similar question has been asked but I have not found a clear solution. I'm trying to mock a private field from a large class. The private field gets instantiated in some earlier method and I'm trying to unit test a latter method which references the field.

So I have an earlier method in my class:

public bool validateAll(ref DataEntry[] oEntries, string sMediaPlanId, ITemplateGenerator oTempGen)
{
  ...
  // private field that I am trying to mock
  this._sMediaPlanObjective = (MPWrapper.Instance).getMediaPlanObjective(sMediaPlanId);
  ...
}

And I'm trying to Unit test a method that references the private field:

public bool validateFlightObjective(ref MPDataEntry oEntry)
{
  ...
  string entryFlightObjective = oEntry.getFlightObjective();
  string mediaPlanObjective = this._sMediaPlanObjective;

  if (entryFlightObjective != mediaPlanObjective)
  {
    return false;
  }
  ...

  return true;      
}

Given that I have a large class and this is just one method I want to test, is there a possible way to just mock this private field? Am I missing something basic or should I consider some other approach?

Samuel Heaney
  • 773
  • 1
  • 8
  • 14
  • As mentioned in the answers, you could (should) avoid this with some refactoring effort. If you still don't want to do that, you could try a stronger mocking framework like Typemock Isolator or Moles. – seldary Jun 27 '12 at 08:44

3 Answers3

5

You can't mock anything that's private, static, or essentially - non overridable (this comes as a free mocking libraries limitation).

What you usually do in such situations (when it appears that private member has to be tested), is extracting your private member to a separate class and inject it to tested class as a dependency.

In your case, you actually need to extract code that creates _sMediaPlanObjective, which is this line:

this._sMediaPlanObjective =
    (MPWrapper.Instance).getMediaPlanObjective(sMediaPlanId);

Object that provides getMediaPlanObjective method should be injected to your tested class. If you do so, you can simply mock that object and tell it to return mocked version of _sMediaPlanObjective.

Community
  • 1
  • 1
k.m
  • 30,794
  • 10
  • 62
  • 86
  • Would this mean having to call validateAll() to set up the mocked version of the private member so that I can test validateFlightObjective()? Or would it be better practice to make some public/protected accessor to setup the private member. – Samuel Heaney Jun 27 '12 at 14:48
  • @SamuelHeaney: most likely so. If assignment to private field is done *only* in `validateAll` method (and cannot be done elsewhere, say in constructor once dependency is injected), then it needs to be called to set the mock. Adding extra accessor solely for the purpose of unit testing should be **last resort**. – k.m Jun 29 '12 at 14:36
0

You can use JustMock framework. For example:

double value = 0;
var fakeFilterSetHelper = Mock.Create<FilterSetHelper>(Behavior.CallOriginal);
Mock.NonPublic.Arrange<double>(fakeFilterSetHelper, memberName: "GetPriceRangeFromSession").Returns(value);
Sergii Fasolko
  • 188
  • 1
  • 7
-1

There is no reason to have any kind of tests on private fields.

using an object you can reference to the public methods as the object API. the object itself can have it's changing state according to the operation you perform on it - but it will be reflected in other public methods / access to DAL (DB / Registry / File/ any other resource that is not in memory)

So in your case you can have a unit tests like that:

call the method that initializes the private field as you expect it to and -

  • Call validateFlightObjective with a parameter that you know that have to return false according to the _sMediaPlanObjective "wanted to be state", and verify that the result is false.

  • Call validateFlightObjective with a parameter that you know that have to return true according to the _sMediaPlanObjective "wanted to be state", and verify that the result is true.

If you see that it is hard to test this object, then that might be a "smell" - maybe you have more than one responsibility there and you should start refactoring and split the class to smaller classes which will be easier to test

That it a bit long but i hope it was helpful

eyossi
  • 4,230
  • 22
  • 20
  • 1
    I don't want to test the private field itself. Wouldn't calling the method that initializes the private field violate the isolation of behavior in the unit test? Also, calling it would mean calling several other methods that need to be called sequentially and access a DB. – Samuel Heaney Jun 27 '12 at 14:02