6

痣可以通过两种方式使用:

手动

  1. 包括【装配:MoleType(typeof(_type_to_instrument))】
  2. 指定 [HostType("Moles")]
  3. 调用 Microsoft.Moles.Framework.Moles.MoleRuntime.SetMole(Delegate _stub, object _receiver, MethodInfo 方法);

动态地

  1. 添加一个 {project name}.moles 文件:将程序集指定为 mole。例如 <Moles xmlns="http://schemas.microsoft.com/moles/2010/"> <Assembly Name="Samples.Moles"/> </Moles>
  2. 构建并包含对 MolesAssemblies/{project_name}.Moles.dll 的引用
  3. 使用 M{class_name} 自动生成的鼹鼠类。

我注意到的是,使用动态程序集不需要测试项目声明“moled 程序集”属性。这减少了开销,开发人员只需要使用主机类型来装饰每个测试方法。但进一步的测试不需要跟踪要检测的类型。

查看 molesassemblies 中自动生成的代码(使用反汇编程序),很容易找到所需的检测属性。但是,尝试编写我自己的“mole 程序集”,基本上替换自动生成的程序集,并不起作用,并且运行时抱怨我的类型需要被检测。我很好奇我错过了什么。

我注意到自动生成的 moles 代码声明了必要的 MoledAssembly 属性。但是在我的测试中,测试项目似乎要声明这个属性;它不能由项目的引用程序集声明。但是,在使用自动生成的程序集的情况下,它似乎可以将属性声明为“外部”。这是我基于反汇编自动生成的 moles dll 所看到的假设;我找不到任何其他区别。但是,正如我试图解释的那样,从反汇编的自动生成的 moles dll 中复制所有代码(和属性)并构建我自己的引用程序集在运行时失败,说我没有标记需要检测的测试中的程序集(即标有 MoledAssembly) - 只是在我引用的程序集中。

- 更新

在这一点上(可能是由于我误解了我的代码缺少什么)我觉得我们需要非常具体地了解哪些程序集有什么。假设我们有 4 个 dll:

  1. Test.dll:mstest 项目。不声明MoledAssembly
  2. Moles.dll:*.moles在项目中使用文件时创建的自动生成的 dll。引用第 4 个 dll,(参见 #4)Sealed。声明[assembly: MoledAssembly("Sealed")]。请注意,我正在尝试在没有此 dll 的情况下完成手动痣注入 - 它只是一个概念参考或用于我们的讨论或故障排除。
  3. MyMoles.dll:我从源代码编译的自动生成的Moles.dll.
  4. Sealed.dll:包含被测代码。

在答案/评论/问题中 - 让我们根据此列表参考每个部分。

4

1 回答 1

4

当使用非自动生成的模块化装配时,装配属性是必需的。出于必要,Visual Studio的Moles 工具会自动提醒编译器存在生成的程序集。

通过 Visual Studio 添加 Moles 程序集时,在项目构建之前不会生成 moles 程序集。此外,不可能为尚不存在的程序集包含程序集属性。这样做会导致编译器失败。因此,Moles 也有必要在编译器命令行中动态添加命令,生成 Moled 程序集,然后从项目中正确引用它们。

使用手动生成的摩尔装配体时,必须包含装配体属性,因为由于装配体不是自动生成的,摩尔工具不知道它的存在。程序员必须为 Moles 做这项工作。

如果你想走这么远,你可以在编译器参与之前使用代码生成。PERL 可以在需要时轻松注入必要的程序集属性。当编译器收到代码时,它已经注入了属性。

支持我的答案的实验:

我能够重现您的问题。我还能够通过在using语句块下方添加程序集属性来解决该问题。我采取了以下步骤来构建我的示例应用程序:

  1. 创建了一个名为 ClassLibrary2 的 .NET 4.0 C# 类库项目。
  2. 在 Class1 中创建了以下方法:

    public string TestString() { return "原始值。"; }

  3. 通过右键单击 TestString 方法声明,然后选择Create Unit Tests...创建了一个测试项目(TestProject1) (懒惰,我知道。)

  4. 从 Class1Test.cs 中删除多余的废话,留下 TestStringTest()。
  5. 为 mscorlib 添加了一个 moles 程序集。(回想起来,另一个懒惰的捷径,也是一个不必要的步骤。我在这里注意到它,因为这是我所做的。)
  6. 为 ClassLibrary2 添加了一个 moles 程序集。
  7. 使用默认的Any CPU配置文件编译的解决方案。
  8. 使用 Redgate(对不起,@payo)反编译 ClassLibrary2.Moles
  9. 添加了一个名为 MoleClassLibrary 的新类库项目。
  10. 将反编译后的 MClass1 和 SClass1 代码复制到 MoleClassLibrary 中。
  11. 从 TestProject1 中删除了 Class1.moles 文件和程序集。
  12. 从 TestProject1 中删除了(不必要的)mscorlib.moles 文件和程序集。
  13. 添加了对 TestProject1 的 MoleClassLibrary 引用。
  14. 更新了Class1Test.cs 中的using语句。
  15. 构建解决方案。
  16. 使用Visual Studio 2010测试视图窗口执行 TestStringTest() 。
  17. 测试失败,产生详细信息:

测试方法 TestProject1.Class1Test.TestStringTest 抛出异常:Microsoft.Moles.Framework.Moles.MoleNotInstrumentedException: 未检测 System.String ClassLibrary1.Class1.TestString()要解决此问题,请在测试项目中添加以下属性:

使用 Microsoft.Moles.Framework;[程序集:MoldAssembly(typeof(ClassLibrary1.Class1))]

我将推荐的程序集属性添加到文件中。这样做之后,测试方法运行成功。我怀疑编译器会自动引用生成的组合程序集,从而不再需要程序集属性。我尝试将 MoleClassLibrary 二进制文件复制到 MolesAssemblies 目录并创建一个 MoleClassLibrary.moles 文件,以测试这个理论。仅当我包含程序集属性时测试才通过。这个结果与我的假设没有定论。

这是 Class1Test.cs 的代码:

using ClassLibrary1;
using Microsoft.Moles.Framework;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MoleClassLibrary;
[assembly: MoledAssembly(typeof(ClassLibrary1.Class1))]

namespace TestProject1
{
    [TestClass()]
    public class Class1Test
    {
        [TestMethod()]
        [HostType("Moles")]
        public void TestStringTest()
        {
            var target = new Class1();
            var expected = "Mole value.";
            string actual;
            MClass1.AllInstances.TestString = value => expected;
            actual = target.TestString();
            Assert.AreEqual(expected, actual);
        }
    }
}
于 2011-06-09T16:37:40.527 回答