To return a "manual override" value from a factory, is it better to check the null value or the logical switch?

Suppose we have a method like

public static IThing getTheThing() { return internalThingGetter(); } 

And we want for debugging or unit testing purposes, we will propose an easy strategy to manually override this.

 private static IThing _thingManualOverride; public static IThing getTheThing() { if (/*some condition*/) return _thingManualOverride; else return internalThingGetter(); } 

Better check _thingManualOverride != null or enter a new boolean and check for example _shouldOverride ?

Or is there a more solid template to use here?

EDIT: Some goals to meet:

  • Suppose it is important to maintain an interface. A lot of code uses this static method, and modifying it is a good goal, but expensive.
  • Both checks are "correct" if the override is null , we can safely assume that the default course is correct.
+4
source share
4 answers

This is not an answer, just a recommendation. It would be useful to read Chapter 3 of The Art Of Unit Testing , written by Roy Osherov (even better, going out and buying, and reading the whole book is great!). In particular, section 3.4.5 (below is a link to a sample chapter 3 containing a section):

The Art of Device Testing - Example Chapter 3

Update: at your request an example of using the static factory class:

 static class ThingFactory { private static IThing _thingManualOverride = null; public static IThing getTheThing() { if (_thingManualOverride != null) return _thingManualOverride; return new internalThingGetter(); } public static void SetThing(IThing thing) { _thingManualOverride = thing; } } 

I will add that I do not like to use this template. If you have the option of refactoring, it would be wise to consider it. The main reason I don't like to use this is that after each test you have to remember the reset state (call the SetThing method with a zero parameter) so that you do not affect other tests using your manual control.

+1
source

If it were _thingManualOverride != null . You can check other fields, for example, the logical name "_IsThingManualOverrideSet", but by mistake of the programmer they can give conflicting values:

 _thingManualOverride = null; _IsThingManualOverrideSet = true; // <-- oops! 

Thus, checking the value itself is the best way.

+2
source

For the unit testing pool, it is better to get rid of the static method in the factory and make a virtual method. That way you can replace its return value with mocks.

 class Factory{ public virtual IThing getTheThing() { return internalThingGetter(); } } 

In tests using the Moq framework:

 var m = new Mock<Factory>(); m.Setup(f=>f.getTheThing()) .Returns(thingManualOverride); 
0
source

You can create a helper class for this, perhaps something like this:

 public class OverridableValue<T> { private readonly Func<T> OriginalValueGetter; private Func<T> ValueGetter; public OverridableValue(Func<T> valueGetter) { this.OriginalValueGetter = valueGetter; this.ValueGetter = OriginalValueGetter; } public T Value { get { return ValueGetter(); } } public void SetValueOverride(T value) { if (value == null) ValueGetter = OriginalValueGetter; else ValueGetter = () => value; } } 

Usage may look like this:

 private static readonly OverridableValue<IThing> _thingManualOverride = new OverridableValue<IThing>(internalThingGetter); public static IThing getTheThing() { return _thingManualOverride.Value; } 

If overriding is as simple as:

 _thingManualOverride.SetValueOverride(new Thing2()); 

You can easily replace the null check in SetValueOverride with something else, or simply define a new method for RemoveOverride() , which will help when the null value is considered a valid override:

 public void SetValueOverride(T value) { ValueGetter = () => value; } public void RemoveOverride() { ValueGetter = OriginalValueGetter; } 

Another advantage is that this override should (I think) be generally thread safe (you will not be in the case where some IsOverriddenFlag are true , but then do not have an override value).

EDIT: you can override the value in the Value installer, but I thought it would look weird in practice:

 public T Value { get { return ValueGetter(); } set { if (value == null) ValueGetter = OriginalValueGetter; else ValueGetter = () => value; } } myThing = _thingManualOverride.Value; //Thing1 _thingManualOverride.Value = new Thing2(); myThing = _thingManualOverride.Value; //Thing2 _thingManualOverride.Value = null; myThing = _thingManualOverride.Value; //Thing1 ... not null!? 
0
source

All Articles