我正在尝试为我的队列创建一个抽象层,以实现更好的集成测试。真正的队列是通过EasyNetQ的RabbitMq。
在我的程序中,我订阅了一些事件,这些事件将方法链接到某些事件类型-当事件发布时,我希望该方法执行。当使用真实的东西时,这很不错。
但是,它确实使我的测试依赖于RabbitMq服务器,并且确实使代码执行异步,这使得很难确定何时应该将测试视为完成。
我不想用这个问题来讨论在测试中抽象化RabbitMq的决定。
要创建在我的测试中使用的存根,我需要存储对事件处理程序的引用-并且在相关类型的事件随后发布之后,我需要执行事件处理程序。
所以我想我需要像下面写的代码。我可以将事件处理程序存储为“委托”,但是如何调用它们呢? RabbitMq事件处理程序的格式为Func,其中T是处理程序处理的事件的类型。
Func<int, Task> handle1 = ...;
Func<string, Task> handle2 = ...;
List<> l = new List<>();
l.Add( handle1);
l.Add( handle2);
foreach(Func f in l)
{
if (f-parameter is string)
{
f("");
}
if (f-parameter is int)
{
f(1);
}
}
答案 0 :(得分:0)
我坚决反对在任何代码中丢失强类型,我认为您不应尝试通过创建“任何内容”列表来解决问题。
另一方面,我不知道您的代码,如果这是唯一的方法,您可以尝试以下方法:
Func<int, Task> f1 = i => Task.FromResult(i);
Func<string, Task> f2 = s => Task.FromResult(s);
var list = new List<object>
{
f1,
f2
};
foreach(var anything in list)
switch(anything)
{
case Func<int, Task> intFunction: intFunction(1); break;
case Func<string, Task> strFunction: strFunction("text"); break;
default: throw new ArgumentException($"I'm not prepared to deal with {anything} function prototype.");
}
此代码使用了C#7中的一些很棒的功能,即模式匹配(切换对象的类型)和内联变量(int / strFunction)。
答案 1 :(得分:0)
我得到了以下解决方案。它使我完全可以完全不使用RabbitMq,并根据需要激活每个已发布消息的事件处理程序。此外,它没有事件类的特定名称,因此我可以将其重新用于RabbitMq解决方案的所有集成测试。
您可以说丢失的那张是
var dynamicInvoke = d1.DynamicInvoke(o)
我也有一个“真实的”前端,可以将调用中继到实际运行的应用程序的RabbitMq / EasyNetQ。
感谢您加入@ensisNoctis!
public class TestBusFront : IBusFront
{
private readonly Dictionary<string, List<Delegate>> _list;
public TestBusFront()
{
_list=new Dictionary<string, List<Delegate>>();
}
public void Publish(object o)
{
var d = GetDelegateListForEvent(o.GetType().FullName);
foreach (var d1 in d)
{
var dynamicInvoke = d1.DynamicInvoke(o);
var task = (Task) dynamicInvoke;
task.Wait();
}
}
public void SubscribeAsync<T>(string s, Func<T, Task> handle)
{
var delegates = GetDelegateListForEvent(typeof(T).FullName);
delegates.Add(handle);
}
private List<Delegate> GetDelegateListForEvent(string eventName)
{
if(!_list.ContainsKey(eventName))
_list.Add(eventName,new List<Delegate>());
return _list[eventName];
}
public void Dispose()
{
}
}