微软鼹鼠,动态仪器

发布于 2024-11-14 18:46:19 字数 1540 浏览 3 评论 0原文

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

手动

  1. 包含 [ assembly: MoledType(typeof(_type_to_instrument))]
  2. 指定 [HostType("Moles")]
  3. 调用 Microsoft.Moles.Framework.Moles.MoleRuntime.SetMole(Delegate _stub, object _receiver, MethodInfo方法);

动态

  1. 添加一个{项目名称}.moles文件:指定程序集为mole。例如 <程序集名称=“Samples.Moles”/>
  2. 构建并包含对 MolesAssemblies/{project_name}.Moles.dll 的引用
  3. 使用 M{class_name} 自动生成的 Moles 类。

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

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

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

-- 更新

此时(可能是由于我对代码缺少的内容的误解)我觉得我们需要非常具体地了解哪些程序集有哪些内容。假设我们有 4 个 dll:

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

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

Moles can be used in two ways:

Manually

  1. Including [assembly: MoledType(typeof(_type_to_instrument))]
  2. Specify [HostType("Moles")]
  3. Call Microsoft.Moles.Framework.Moles.MoleRuntime.SetMole(Delegate _stub, object _receiver, MethodInfo method);

Dynamically

  1. Add a {project name}.moles file: specifying assembly to mole. e.g.
    <Moles xmlns="http://schemas.microsoft.com/moles/2010/">
    <Assembly Name="Samples.Moles"/>
    </Moles>
  2. Build and include reference to MolesAssemblies/{project_name}.Moles.dll
  3. Use M{class_name} auto-generated mole classes.

What I noticed is that using the dynamic assembly doesn't require the test project to declare 'moled assemblies' attributes. This reduces the overhead, and a developer need only decorate each test method with the host type for moles; but further testing doesn't need to keep track of what types to instrument.

Looking at the auto-generated code (using a disassembler) in the molesassemblies, it is easy to find that the needed instrumentation attributes. However, trying to write my own 'mole assembly', essentially replacing the autogenerated one, doesn't work and the runtime complains that my type needs to be instrumented. I am curious what I'm missing.

I noticed that the autogenerated moles code declared the necessary MoledAssembly attributes. But in my tests, the test project seems to have to declare this property; it can't be declared by a referenced assembly to the project. However, in the case with the autogenerated assembly, it APPEARS the attribute can be declared "outside". This is my assumption based what I can see with disassembling the autogenerated moles dll; I cannot find any other difference. However, as I'm trying to explain, copying all the code (and attributes) from the disassembled autogenerated moles dll and building my own referenced assembly fails at runtime saying I have not marked the needed assembly-in-test to be instrumented (i.e. marked with the MoledAssembly) - tho it has, simply in my referenced asssembly.

-- update

At this point (likely due to my misunderstanding of what my code is missing) I feel we need to be very specific about what assembly has what. Let's say we have 4 dlls:

  1. Test.dll: The mstest project. Does not declared MoledAssembly.
  2. Moles.dll: The autogenerated dll created when using a *.moles file in your project. References the 4th dll, (see #4) Sealed. Declares [assembly: MoledAssembly("Sealed")]. Note that I'm trying to accomplish manual mole injection without this dll - it's only a conceptual reference or to be used in our discussion or troubleshooting.
  3. MyMoles.dll: My from-source compiled version of the autogenerated Moles.dll.
  4. Sealed.dll: Contains the code-under-test.

In answers/comments/questions - let's refer to each part according to this list.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

潜移默化 2024-11-21 18:46:19

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

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

当使用手动生成的 moled 程序集时,必须包含程序集属性,因为 Moles 工具由于程序集不是自动生成的而无法意识到其存在。程序员必须为鼹鼠做这项工作。

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

支持我的答案的实验:

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

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

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

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

  4. 删除了多余的废话Class1Test.cs,留下 TestStringTest()。
  5. 为 mscorlib 添加了 Moles 程序集。 (回想起来,这是另一个懒惰的捷径,也是一个不必要的步骤。我在这里记下它,因为这是我所做的事情。)
  6. 为 ClassLibrary2 添加了一个摩尔程序集。
  7. 使用默认的任何 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:
系统字符串
ClassLibrary1.Class1.TestString() 是
未检测
要解决此问题
问题,添加以下属性
测试项目:

使用 Microsoft.Moles.Framework;
[集会:
MoledAssembly(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);
        }
    }
}

The assembly attribute is required, when using moled assemblies that are not automatically generated. The Moles Tools for Visual Studio automatically alert the compiler to the presence of generated assemblies, out of necessity.

When adding a Moles assembly via Visual Studio, the mole assembly is not generated until the project is built. Furthermore, it is impossible to include an assembly attribute for an assembly that does not already exist. Doing so will cause the compiler to fail. Therefore, it is necessary for Moles to also dynamically add commands to the compiler command line, to generate the moled assemblies, and then properly reference them from the project.

When using a manually-generated, moled assembly, it is necessary to include an assembly attribute, because the Moles tools is unaware of its presence by virtue of the assembly not being auto-generated. The programmer has to do the job for Moles.

If you want to go so far, you may employ code generation, before the compiler engages. PERL can easily inject the necessary assembly attribute, where needed. When the compiler receives the code, it will already have the attribute(s) injected.

An Experiment to Back my Answer:

I was able to reproduce your issue. I was also able to resolve the problem, by adding an assembly attribute, below the using statement block. I took the following steps, to build my sample application:

  1. Created a .NET 4.0 C# Class Library project, named ClassLibrary2.
  2. Created the following method, in Class1:

    public string TestString() { return "Original value."; }

  3. Created a test project (TestProject1), by right-clicking the TestString method declaraction, and then selecting Create Unit Tests... (Lazy, I know.)

  4. Deleted the extra crap out of Class1Test.cs, leaving TestStringTest().
  5. Added a moles assembly for mscorlib. (Another lazy shortcut, and an unnecessary step, in retrospect. I note it here, because it is something I did.)
  6. Added a moles assembly for ClassLibrary2.
  7. Compiled solution using the default Any CPU profile.
  8. Used Redgate (sorry, @payo) to decompile ClassLibrary2.Moles
  9. Added a new Class Library project, named MoleClassLibrary.
  10. Copied the decompiled MClass1 and SClass1 code into MoleClassLibrary.
  11. Removed the Class1.moles file and assemblies from TestProject1.
  12. Removed the (unnecessary) mscorlib.moles file and assemblies from TestProject1.
  13. Added a MoleClassLibrary reference to TestProject1.
  14. Updated the using statement in Class1Test.cs.
  15. Build solution.
  16. Executed TestStringTest(), using the Visual Studio 2010 Test View window.
  17. The test fails, producing details:

Test method
TestProject1.Class1Test.TestStringTest
threw exception:
Microsoft.Moles.Framework.Moles.MoleNotInstrumentedException:
The System.String
ClassLibrary1.Class1.TestString() was
not instrumented
To resolve this
issue, add the following attribute in
the test project:

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

I added the recommended assembly attribute to the file. After doing so, the test method ran successfully. I suspect the compiler is automatically referencing generated moled assemblies, removing the need for the assembly attribute. I tried copying the MoleClassLibrary binaries to the MolesAssemblies directory and creating a MoleClassLibrary.moles file, to test this theory. The test passed only when I included the assembly attribute. This result is inconclusive to my hypothesis.

Here's the code for 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);
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文