如何替换 MEF 容器中导出的零件/对象?
我正在运行一个 WPF 应用程序,它需要影响 UI 的所有操作都在 UI 线程上。 WPF 还提供了一个 Dispatcher 类来处理此问题 - 因此我将其提取到依赖项中。
public interface UIActionExecutor
{
void Do(Action action);
}
因此,在我的生产代码中,我使用委托给 WPF 调度程序的导出实现。我使用 MEF 进行 DI。
现在的问题是,在我的验收测试中,我需要用 Mock 替换容器中响应 UIActionExecutor 的部分/对象。因此,我需要从容器中删除 ExecutorUsingWpfDispatcher
并在其位置添加 MockUIActionExecutor
。这听起来很简单(如果我没有使用 MEF)...但是我的搜索技能并没有帮助我找到如何使用 MEF 容器执行此操作的答案?
更新: 如果有人想知道该解决方案的工作原理/原因 - 请阅读 Glenn Block 的博客文章#2。这就是我最终使用的
var defaultExportProvider = new CatalogExportProvider(__defaultCatalog);
var catalogOfMocks = new AssemblyCatalog(assemblyExportingMocks);
// order of params important (precedence left to right)
__container = new CompositionContainer(catalogOfMocks, defaultExportProvider);
defaultExportProvider.SourceProvider = __container
I have a WPF app running, which needs all operations that affect the UI to be on the UI Thread. WPF also provides a Dispatcher class that handles this - so I extracted that into a dependency.
public interface UIActionExecutor
{
void Do(Action action);
}
So in my production code, I use an exported implementation which delegates to the WPF Dispatcher. I'm using MEF for DI.
Now the problem, in my acceptance tests, I need to replace the part / object in the container that responds to UIActionExecutor
by a Mock. So I need to remove ExecutorUsingWpfDispatcher
from my container and add MockUIActionExecutor
in its place. This sounds pretty simple (if I was not using MEF)... but my searching skills haven't helped me find an answer as to how to do this with the MEF container ?
Update:
If anyone wants to know why/how the solution works - read Glenn Block's blog post#2. This is what I ended up using
var defaultExportProvider = new CatalogExportProvider(__defaultCatalog);
var catalogOfMocks = new AssemblyCatalog(assemblyExportingMocks);
// order of params important (precedence left to right)
__container = new CompositionContainer(catalogOfMocks, defaultExportProvider);
defaultExportProvider.SourceProvider = __container
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
DI 容器负责将所有内容连接在一起。
单元测试负责单独测试单个代码单元。模拟用于替换依赖项。因此原则上 DI 容器不应该在单元测试中使用。它与“单元测试”的定义相矛盾。(1)
但是,我当然可以理解,除了单元测试之外,您可能还希望进行自动化集成测试,并且您可能希望使用 MEF 但在此类测试中替换某些 MEF 部分。您可以这样做:
(1)从您的博客来看,我确信您已经知道这一点。但其他人也会阅读这个答案,所以我想澄清术语“单元测试”。
A DI container is responsible for wiring everything together.
A unit test is responsible for testing a single unit of code in isolation. Mocks are used to replace dependencies. So in principle a DI container should not be used in a unit test. It contradicts the definition of "unit test".(¹)
However, I can certainly understand that you might want to do automated integration tests in addition to unit tests, and you might want to use MEF yet replace certain MEF parts in such a test. You can do that like this:
(¹)Judging from your blog, I'm sure you already know this. But others will also read this answer, so I wanted to be clear about the term "unit test".
无法让接受的解决方案发挥作用。下面的代码应该可以工作,并且 AggregateExportProvider 的文档中描述了优先级。
Could not get the accepted solution to work. Below code should work and precedence is described in the documentation for
AggregateExportProvider
.