如何注入与 Moq 一起使用的模拟程序集
How to inject a mock Assembly for use with Moq
我的控制器中有一个方法 returns 将当前正在执行的程序集中的数据属性化为局部视图。
在这个例子中,我只是提取标题,但我需要用它做更多的事情。
控制器:
var title = "";
var asm = Assembly.GetExecutingAssembly();
var attrs = asm.GetCustomAttributes(typeof(AssemblyTitleAttribute));
var titleAttr = (AssemblyTitleAttribute)attributes[0];
title = titleAttr.Title;
return PartialView("_Build", title);
在 Moq 中编写单元测试时,我需要找到一种方法将 Assembly 属性注入到 mock 中,以便在我 运行 控制器测试时验证是否生成了正确的属性,然后用我的断言做 x 或 y。
单元测试:
//Arrange
//The magic I need to happen.
//Act
var controller = GetController();
var result = controller.MyMethod() as PartialViewResult;
var title = result.Model;
//Assert
Assert.AreEqual("Title", title); //currently static, need to verify against a mock
我知道这是一组极其简单的代码,但此时我只需要概念证明。
有没有什么好的方法来创建一个假的Assembly?
我需要使用 System.Reflection.Emit 吗?
由于这是静态类型信息,因此每次构建只需评估一次。考虑在应用程序启动时使用此信息填充静态集合(例如字典)。那时你可以将你的字典注入控制器,或者你可以修改你的配置来访问字典并只注入你需要的值。事实上,如果这不会失控,最好只使用 "build" 或 "title" 之类的命名字符串实例,甚至不必将它们放在集合中。
除非逻辑可以包含在您的单元测试直接调用的静态方法中,否则我不会为尝试围绕解析程序集属性进行单元测试的麻烦而烦恼。从 Web 应用程序的角度来看,最好将此类内容留在控制器之外;引导程序层是一个更合适的位置。
您可以创建一个虚拟方法,例如GetCustomAttributes
提供给定类型的属性。然后在您的测试项目中,一个 testable class 将从控制器 class 派生并覆盖此方法。
Home Controller:
private IDependency _someDependency;
public HomeController(IDependency someDependency)
{
_someDependency = someDependency;
}
public ActionResult MyMethod()
{
var title = "";
var version = "";
IEnumerable<Attribute> attributes = GetCustomAttributes(typeof(AssemblyVersionAttribute)).ToList();
AssemblyVersionAttribute verAttr = attributes.OfType<AssemblyVersionAttribute>().FirstOrDefault();
if (verAttr != null) version = verAttr.Version;
attributes = GetCustomAttributes(typeof(AssemblyTitleAttribute)).ToList();
AssemblyTitleAttribute titleAttr = attributes.OfType<AssemblyTitleAttribute>().FirstOrDefault();
if (titleAttr != null) title = titleAttr.Title;
return PartialView("_Build", title + version);
}
public virtual IEnumerable<Attribute> GetCustomAttributes(Type attributeType)
{
var asm = Assembly.GetExecutingAssembly();
var attrs = asm.GetCustomAttributes(attributeType);
return attrs;
}
Test:
[TestClass]
public class MyMethodTest
{
[TestMethod]
public void MyMethod_WhenCalled_PartialViewIsReturned()
{
// Arrange
// The magic I need to happen.
Mock<IDependency> dependencyStub = new Mock<IDependency>();
// dependencyStub.Setup(...).Returns(...);
var controller = new TestableHomeController(dependencyStub.Object)
{
UseFakeAttributes = true
};
// Act
var result = controller.MyMethod() as PartialViewResult;
// Assert
var model = result.Model;
Assert.AreEqual("MyFakeTitle1.0.0.0", model); // currently static, need to verify against a mock
}
private class TestableHomeController : HomeController
{
public bool UseFakeAttributes { get; set; }
public TestableHomeController(IDependency someDependency)
:base(someDependency)
{ }
public override IEnumerable<Attribute> GetCustomAttributes(Type attributeType)
{
return UseFakeAttributes
? new List<Attribute>
{
new AssemblyTitleAttribute("MyFakeTitle"),
new AssemblyVersionAttribute("1.0.0.0"),
new AssemblyDescriptionAttribute("Assembly fake description")
// next attributes ...
}.Where(a => a.GetType() == attributeType)
: base.GetCustomAttributes(attributeType);
}
}
}
我的控制器中有一个方法 returns 将当前正在执行的程序集中的数据属性化为局部视图。
在这个例子中,我只是提取标题,但我需要用它做更多的事情。
控制器:
var title = "";
var asm = Assembly.GetExecutingAssembly();
var attrs = asm.GetCustomAttributes(typeof(AssemblyTitleAttribute));
var titleAttr = (AssemblyTitleAttribute)attributes[0];
title = titleAttr.Title;
return PartialView("_Build", title);
在 Moq 中编写单元测试时,我需要找到一种方法将 Assembly 属性注入到 mock 中,以便在我 运行 控制器测试时验证是否生成了正确的属性,然后用我的断言做 x 或 y。
单元测试:
//Arrange
//The magic I need to happen.
//Act
var controller = GetController();
var result = controller.MyMethod() as PartialViewResult;
var title = result.Model;
//Assert
Assert.AreEqual("Title", title); //currently static, need to verify against a mock
我知道这是一组极其简单的代码,但此时我只需要概念证明。
有没有什么好的方法来创建一个假的Assembly? 我需要使用 System.Reflection.Emit 吗?
由于这是静态类型信息,因此每次构建只需评估一次。考虑在应用程序启动时使用此信息填充静态集合(例如字典)。那时你可以将你的字典注入控制器,或者你可以修改你的配置来访问字典并只注入你需要的值。事实上,如果这不会失控,最好只使用 "build" 或 "title" 之类的命名字符串实例,甚至不必将它们放在集合中。
除非逻辑可以包含在您的单元测试直接调用的静态方法中,否则我不会为尝试围绕解析程序集属性进行单元测试的麻烦而烦恼。从 Web 应用程序的角度来看,最好将此类内容留在控制器之外;引导程序层是一个更合适的位置。
您可以创建一个虚拟方法,例如GetCustomAttributes
提供给定类型的属性。然后在您的测试项目中,一个 testable class 将从控制器 class 派生并覆盖此方法。
Home Controller:
private IDependency _someDependency;
public HomeController(IDependency someDependency)
{
_someDependency = someDependency;
}
public ActionResult MyMethod()
{
var title = "";
var version = "";
IEnumerable<Attribute> attributes = GetCustomAttributes(typeof(AssemblyVersionAttribute)).ToList();
AssemblyVersionAttribute verAttr = attributes.OfType<AssemblyVersionAttribute>().FirstOrDefault();
if (verAttr != null) version = verAttr.Version;
attributes = GetCustomAttributes(typeof(AssemblyTitleAttribute)).ToList();
AssemblyTitleAttribute titleAttr = attributes.OfType<AssemblyTitleAttribute>().FirstOrDefault();
if (titleAttr != null) title = titleAttr.Title;
return PartialView("_Build", title + version);
}
public virtual IEnumerable<Attribute> GetCustomAttributes(Type attributeType)
{
var asm = Assembly.GetExecutingAssembly();
var attrs = asm.GetCustomAttributes(attributeType);
return attrs;
}
Test:
[TestClass]
public class MyMethodTest
{
[TestMethod]
public void MyMethod_WhenCalled_PartialViewIsReturned()
{
// Arrange
// The magic I need to happen.
Mock<IDependency> dependencyStub = new Mock<IDependency>();
// dependencyStub.Setup(...).Returns(...);
var controller = new TestableHomeController(dependencyStub.Object)
{
UseFakeAttributes = true
};
// Act
var result = controller.MyMethod() as PartialViewResult;
// Assert
var model = result.Model;
Assert.AreEqual("MyFakeTitle1.0.0.0", model); // currently static, need to verify against a mock
}
private class TestableHomeController : HomeController
{
public bool UseFakeAttributes { get; set; }
public TestableHomeController(IDependency someDependency)
:base(someDependency)
{ }
public override IEnumerable<Attribute> GetCustomAttributes(Type attributeType)
{
return UseFakeAttributes
? new List<Attribute>
{
new AssemblyTitleAttribute("MyFakeTitle"),
new AssemblyVersionAttribute("1.0.0.0"),
new AssemblyDescriptionAttribute("Assembly fake description")
// next attributes ...
}.Where(a => a.GetType() == attributeType)
: base.GetCustomAttributes(attributeType);
}
}
}