1

I'm writing unit tests using C# and Microsoft Fakes. The class I want to test subscribes to a sizable number of events defined in a service. The Service reference is private. Fakes has generated a Stub of the service class' Interface. I'm trying to write an extension method for the Stub that will allow me to determine whether an event, that I identify by name, has a subscriber or not.

I've searched for and found some examples but none have applied specifically to what I am doing and don't work. I think because of the Stub.

For example, this code is borrowed from another StackOverflow post but doesn't work because it doesn't find any event by name:

var rsEvent = relayService.GetType().GetEvent(eventName + "Event", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

Part of the reason is because Fakes appends Event to the name but even when I append "Event" to the name GetEvent() still doesn't recognize the event. The ONLY way I can retrieve it is by using GetMember(). OK. That's great but how do I convert a MemberInfo object to an Event of Action<string> so that I can determine whether the event has been subscribed? Or is there a better way? All I want to know is whether the named event has a subscriber.

public interface IRelayService
{
    ...
    event Action<string> DisplayHandoffConversationTextEvent;
    ...
}
public class MainWindowViewModel : ViewModelBase
{
    ...
    private readonly IRelayService _relayService;
    ....
    public MainWindowViewModel()
    {
        ...
        _relayService = SimpleIoc.Default.GetInstance<IRelayService>();
        ...
    }

    public void InitializeServices() // method to be tested
    {
        ...
         _relayService.DisplayHandoffConversationTextEvent += OnDisplayHandoffConversationText;
        ...
    }
}
[TestClass]
public class MainWindowViewModelTests
{
    [ClassInitialize]
    public static void ClassInitialize(TestContext testContext)
    {
        ...
        _relayService = new StubIRelayService();
        ...
    }

    [TestMethod]
    public void InitializeServices_Test()
    {
        // Arrange
        var mwvm = new MainWindowViewModel();

         // Act
         mwvm.InitializeServices();

        // Assert

 Assert.IsTrue(_relayService.DoesEventHaveSubscriber("DisplayHandoffConversationTextEvent"));
            Assert.IsFalse(_relayService.DoesEventHaveSubscriber("AdminCanceledCallEvent"));
    }

}
public static class StubIRelayServiceExtensions
{
    public static bool DoesEventHaveSubscriber(this IRelayService relayService, string eventName)
    {
        var rsEvent = relayService.GetType().GetMember(eventName + "Event",
                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
        if (rsEvent.Length > 0)
        {
            var member = rsEvent[0];
            // What do I do here?
            return true;
        }
        return false;
    }
}

In the extension method, how do I determine whether the event has a subscriber? I'm stumped.

TIA

Dar
  • 383
  • 1
  • 5
  • 16
  • 1
    writing code in your class that is only used in unit tests is code smell. – TheBatman Apr 24 '19 at 17:48
  • Fair enough. So how do you test whether events belonging to a private object have received subscribers or not? Bear in mind, the methods subscribing to the events are also private. – Dar Apr 24 '19 at 18:21
  • 1
    You generally do not unit test private methods. You test the side-effects in the public methods. There are dirty ways around this, some of which is discussed [here](https://stackoverflow.com/questions/31308322/test-a-public-method-which-calls-a-private-method-using-nunit), but these methods are only really ideal for legacy code where you can't refactor into a better architecture. Make sure you understand SOLID and try to refactor if needed. – TheBatman Apr 24 '19 at 18:26
  • I've been thinking this over and talking to another seasoned developer. Neither of us is convinced this is a code smell because I'm extending the Stub class in the Unit test project. The extension method is not available to the production code. – Dar Apr 24 '19 at 18:58
  • Fair enough, I didn't know this was being extended only in your Test solution. I would ask the seasoned developer what his thoughts are on unit testing private methods. – TheBatman Apr 24 '19 at 19:00
  • If you look at the code example above, you'll see that the method I want to test is public. But the method's sole purpose is to subscribe other methods to events in the _relayService object, which is private. I want to know that this method did everything I expect and am trying to find a way to verify that it met my expectations. Is there a better way? Do I just decorate the method with [ExcludeFromCodeCoverage] and move on? – Dar Apr 24 '19 at 19:35

1 Answers1

1

Just in case this isn't heresy, here is how I got the extension method to do what I wanted:

    public static class StubIRelayServiceExtensions
    {
        public static bool EventHasSubscriber(this IRelayService relayService, string eventName)
        {
            var eventField = relayService.GetType().GetField(eventName + "Event",
                BindingFlags.Public | BindingFlags.Instance);
            object object_value = eventField.GetValue(relayService);
            return object_value != null;
        }
    }
Dar
  • 383
  • 1
  • 5
  • 16