2012-01-29 84 views
0

我的问题并非试图简单地验证方法是否被调用。相反,我有一个方法在对象集合上工作,我想验证所有集合项目上的方法都被调用。使用Moq验证集合中的项目的方法

使用插件模型的示例,其中包含一个包含插件对象集合的插件管理器。每个插件都是PlugIn抽象基类的子类,它提供了一个抽象的Initialize方法。在我的测试中,我想确保每个插件都调用Initialize,而不管它们中的一个是否引发异常(只是大型测试套件的一部分)。

我最初的方法是创建一个mocked插件集合,然后配置被测试的类(PlugInManager)使用mocked对象。然后我通过调用应该遍历集合的PlugInManager.DoWork()来执行测试,并在每个项目上调用DoWork()。

完整的测试代码如下:

[TestMethod()] 
public void MyTest() 
{ 
    // ARRANGE 
    var testParameter = new Something(); 

    var mockPlugIns = new Collection<Mock<PlugIn>>() 
    { 
     new Mock<PlugIn>(), 
     new Mock<PlugIn>(), 
     new Mock<PlugIn>() 
    }; 

    var plugIns = new Collection<PlugIn>(); 

    foreach (var plugIn in mockPlugIns) 
     plugIns.Add(plugIn.Object); 

    var testManager = new PlugInManager() 
    { 
     PlugIns = plugIns 
    }; 

    // ACT 
    testManager.DoWork(testParameter); 

    // ASSERT 
    foreach (var mockPlugIn in mockPlugIns) 
     mockPlugIn.Verify(plugin => plugin.DoWork(testParameter), Times.Once()); 

    // Also tried using It.IsAny<Something>() 
} 

public abstract class PlugIn 
{ 
    abstract void DoWork(Something something); 
} 

public sealed class PlugInManager 
{ 
    public IEnumerable<PlugIn> PlugIns { get; set; } 

    public void DoWork(Something something) 
    { 
     foreach (var plugIn in PlugIns) 
      plugIn.DoWork(something); 
    } 
} 

不幸的是,验证失败的每个项目。

我已经浏览了代码,看到它实际上工作正常,并且每个项目都调用Initialize方法。那么,何时验证失败?

更新#1

我已经更新后显示整个测试方法在一个街区。我也改变了方法,需要一个参数,就像在我的真实代码中一样(现在)。

更新#2

运行测试时,收到的错误是:

Moq.MockException: 
Expected invocation on the mock once, but was 0 times: plugin => plugin.DoWork(It.IsAny<Something>()) 
No setups configured. 
No invocations performed. 

如所提到的,当我通过单元测试步骤我看到,每个插件的实际被调用。然而,出于某种原因,Moq似乎没有注册或识别它。

更新#3

与测试代码的演出之后,我发现我可以使测试通过用一个简单的变化。该测试通过,如果我用下面的替换foreach循环的方法的中间:

plugIns.Add(mockPlugIns[0]); 
plugIns.Add(mockPlugIns[1]); 
plugIns.Add(mockPlugIns[2]); 

我不明白这是怎么发挥作用,并最终喜欢做的项目数量动态的,所以在测试并不总是测试的情况下,有三个,所以使用foreach是我真正需要的。

任何想法?

这实际上并非如此,今天上午进一步测试后,我发现一切工作正常,与原始的foreach循环。我不知道发生了什么变化,但昨晚我尝试了许多不同的变体,而今天早上的代码看起来就像发布的内容一样,无论出于何种原因,测试现在都已经过去了!?!?!?!?

+2

您能提供完整的测试或简化版吗?因为你的方法如果好,它应该工作。我还用你的代码创建了一个repro,它对我来说是绿色的。 – nemesv 2012-01-29 08:42:14

回答

2

这适用于我在LINQPad与Moq 4。我改变的唯一办法是在Times.Once()上加上括号。

void Main() 
{ 
    var MockPlugIns = new Collection<Mock<PlugIn>>() 
    { 
     new Mock<PlugIn>(), 
     new Mock<PlugIn>(), 
     new Mock<PlugIn>() 
    }; 

    var plugIns = new Collection<PlugIn>(); 

    foreach (var mockPlugIn in MockPlugIns) 
     plugIns.Add(mockPlugIn.Object); 

    var testManager = new PlugInManager() 
    { 
     PlugIns = plugIns 
    }; 

    testManager.Initialize(); 

    foreach (var mockPlugIn in MockPlugIns) 
     mockPlugIn.Verify(plugin => plugin.Initialize(), Times.Once()); 
} 

public abstract class PlugIn 
{ 
    public abstract void Initialize(); 
} 

public class PlugInManager 
{ 
    public void Initialize() 
    { 
     foreach (var plugIn in PlugIns) 
     { 
      plugIn.Initialize(); 
     } 
    } 

    public Collection<PlugIn> PlugIns { get; set; } 
} 

UPDATE

我跑更新的测试代码,它通过给下面的实现:

public class PlugInManager 
{ 
    public void DoWork(Something s) 
    { 
     foreach (var plugIn in PlugIns) 
     { 
      plugIn.DoWork(s); 
     } 
    } 

    public Collection<PlugIn> PlugIns { get; set; } 
} 

它通过带或不带你提到的It.IsAny变化。最初的想法是你可能没有将相同的Something实例传递给插件,但It.IsAny会解决这个问题。

简而言之,看起来你在测试中做的一切都是正确的。也许这个问题是在实际实施中。

请在测试失败时发布您的PlugInManager.DoWork和确切错误消息。另外,你使用什么版本的Moq?

UPDATE

我剪切和粘贴代码,并尝试过。我不得不作出一个更改:abstract void DoWorkabstract class PlugIn需要是public。完成更改后,编译并通过测试。如果我将测试的“ACT”部分注释掉,它会失败并显示您看到的错误消息(正如我所预期的那样)。

在您的项目或环境中有所不同。我使用Moq 4.0在Windows 64下运行.NET 4(不是Mono)。你发布的所有内容都是正确的。我会建议您确认您正在运行最新的Moq二进制文件,检查您的项目参考,并尝试一些非常简单的验证测试以确保Moq正在运行。

+0

你的实现基本上就是这样。我已经使用代码更新了帖子以及我收到的错误。 – SonOfPirate 2012-01-30 15:23:45

+0

是的,'public'是一个剪切粘贴错误(我在重新格式化时删除了太多的内容)我使用Moq 4在Windows 7 32位下运行VS 2010,.NET 4。测试在解决方案中,大多数使用Moq,这是唯一的测试给我的问题,看我的更新,我最近的调查结果 – SonOfPirate 2012-01-31 02:57:57

+0

该行应该是'plugIns.Add(mockPlugIns [0] .Object);'。其他在这一点上我不知道发生了什么 – TrueWill 2012-01-31 03:20:35