I've been strugling with a moq setup for a while, and I'd like get some help from you, any help is appreciated.
Basic codes
public interface IMessageHub
{
void Subscribe<T>(string topic, Action<T> callback);
}
Having message hub, where you can subscribe to topics, and if there is a message that was published, it calls the callback with the message.
Every message is derived from
public class MessageBase { }
And for the example, I have created 2 message types:
public class RefreshMessage : MessageBase { }
public class CancelMessage : MessageBase { }
In some part of the code, there is 2 subscribtion for the messages
...
MessageHub.Subscribe<RefreshMessage>("Refresh", RefreshMethod);
MessageHub.Subscribe<CancelMessage>("Cancel", CancelMethod);
...
The callback methods are private, so I can only get them through setup in the unit tests.
private void RefreshMethod(RefreshMessage message) { ... }
private void CancelMethod(CancelMessage message) { ... }
These parts are provided by a framework, so I can't change them.
Unit tests
In the unit tests I want to mock the MessageHub with a Moq , and mock the Subscribe method for every action, and get the callback method that the subscribe method was called with.
Normally, I would have to create 2 setups for every messagetype like this:
var messageHubMock = new Mock<IMessageHub>();
var methods = new List<dynamic>();
//setup for RefreshMessage
messageHubMock.Setup(_=>_.Subscribe(It.IsAny<string>,It.IsAny<Action<RefreshMessage>>())
.Callback<string,Action<RefreshMessage>>((s,a)=> methods.Add(a));
//setup for CancelMessage
messageHubMock.Setup(_=>_.Subscribe(It.IsAny<string>,It.IsAny<Action<CancelMessage>>())
.Callback<string,Action<CancelMessage>>((s,a)=> methods.Add(a));
Setup question
Question is, how can I do the 2 setup in 1 setup?
The following setups ARE NOT WORKING, but showing that those I've tried.
messageHubMock.Setup(_=>_.Subscribe(It.IsAny<string>,It.IsAny<Action<object>>())
.Callback<string,Action<object>>((s,a)=> methods.Add(a));
messageHubMock.Setup(_=>_.Subscribe(It.IsAny<string>,It.IsAny<Action<dynamic>>())
.Callback<string,Action<dynamic>>((s,a)=> methods.Add(a));
messageHubMock.Setup(_=>_.Subscribe(It.IsAny<string>,It.IsAny<object>())
.Callback<string,object>((s,a)=> methods.Add(a));
//does not compile
messageHubMock.Setup(_=>_.Subscribe(It.IsAny<string>,It.IsAny<Action>())
.Callback<string,Action>((s,a)=> methods.Add(a));
messageHubMock.Setup(_=>_.Subscribe(It.IsAny<string>,It.IsAny<Action<MessageBase>>())
.Callback<string,Action<MessageBase>>((s,a)=> methods.Add(a));
Every of these does not fit for the expression, so even though the subscibre was called in the code, Moq does not run the Callback on the setup, because the subscribe was called with "different" arguments.
I suppose I need to create my own expression filter logic on this. Can you help me out, how to create this setup, with 1 setup only?