0

I have a Singleton class, something like this :

public class XConnector : IXConnector
        {

            private static readonly Lazy<XConnector> instance = 
                    new Lazy<XConnector>(() => new XConnector());

            public static XConnector Instance => instance.Value;

            private XConnector()
            {
            }

            public async Task<XConnector> GetData(XConnector con)
            {
            }
      }

How can I mock this class with NSubstitute ?

in other hand : I want something like this

var target = Substitute.For<IXConnector>();

this is a quick Watch when I debug this code

enter image description here any help is welcome.

  • 1
    And what´s the problem? `Substitute.For();` should perfectly work if `IXConnector` is an interface (what I suppose). – MakePeaceGreatAgain Apr 20 '17 at 08:12
  • You can use Mark Seemann's Ambient Context pattern. This will allow you to inject an instance while still providing the intent of the Singleton. – David Osborne Apr 20 '17 at 08:15
  • @HimBromBeere test this code..and see in _target field, you'll see that's null –  Apr 20 '17 at 08:23
  • You need a proxy for `IXConnector`, but in tne watch `target` is of type `ICrmConnectorProxy`. – MakePeaceGreatAgain Apr 20 '17 at 08:29
  • @HimBromBeere can you post your solution please ? –  Apr 20 '17 at 08:38
  • @DavidOsborne I dont see how can I do it, give me an exemple please. –  Apr 20 '17 at 08:40
  • 1
    How does `CrmConnector` rely on `XConnector`? – MakePeaceGreatAgain Apr 20 '17 at 08:55
  • 1
    Anyway I think the `__target`-member is not what you think it is (not sure on the internal implementation however). Just work with the code `var target = Substitute.For();` you allready have. This will give you a proxy-instance of your interface. However it doesn´t know *anything* of your singleton. Maybe yoou should show how you´re using the mock. – MakePeaceGreatAgain Apr 20 '17 at 08:59
  • @HimBromBeere I've fixed, CRMconnector is a typing error. Normally it is XConnector –  Apr 20 '17 at 09:56
  • @HimBromBeere all the problem is there [Just work with the code var target = Substitute.For();] . of corse I have to work with it. the question is how to mock a singleton.. –  Apr 20 '17 at 09:59
  • 1
    There *is no* singleton, just an instance of an interface involved. So show what you´re doing with `target`. – MakePeaceGreatAgain Apr 20 '17 at 10:09

1 Answers1

3

I can't remember the implementation of the Ambient Context pattern, I don't have the book to hand. However, it would look something like this:

public class XConnector : IXConnector
{
    private static IXConnector _instance = new XConnector();

    private XConnector()
    {
    }

    public static IXConnector Current
    { 
       get
       {
           return _instance;
       }
       set 
       {
           // Think about thread-safety
           // Check for null?
           _instance = value;
       }
    }

    public async Task<XConnector> GetData(XConnector con)
    {
    }
}

Then your test can do this:

XConnector.Current = Substitute.For<IXConnector>();

Your functional code can do this, working with the default instance, or the fake one:

XConnector.Current.GetData(...);
David Osborne
  • 6,436
  • 1
  • 21
  • 35
  • You put me on the right path. But I do not think I have my answer. Because the instance is a readonly –  Apr 20 '17 at 11:30
  • 6
    Is that essential? If you want to replace the instance with a fake, you're going to need some way to set it and the current design rules out a constructor. – David Osborne Apr 20 '17 at 11:46