我如何对依赖于 HttpContext.GetGlobalResourceObject 的 class 进行单元测试?
How do I unit test a class that relies on HttpContext.GetGlobalResourceObject?
我正在尝试向 webforms 项目添加测试。有一个静态方法可以从资源文件中获取行。我正在尝试测试的 classes 之一依赖于从资源文件中抓取文本。
public static class MyStaticClass {
public static string getText(String name)
{
String s = HttpContext.GetGlobalResourceObject("MyResources", name).ToString();
return s;
}
}
public class ClassUnderTest
{
// returns: "Hey it's my text"
private string _eg = MyStaticClass.getText("label_in_resources.resx_file")
}
class UnitTests
{
[Test]
public void TestMyClass()
{
ClassUnderTest _cut = new ClassUnderTest();
// errors out because ClassUnderTest utilizes getText
// which requires HttpContext.GetGlobalResourceObject
// ... other stuff
}
}
注意:这些是简单的示例。
问题是我收到测试失败消息:
Message: System.NullReferenceException : Object reference not set to an instance of an object.
根据我的调查,我确定这是因为 HttpContext
在这些测试期间为空。
我看过很多关于模拟的 SO 帖子 HttpContext
但我不认为我完全理解他们到底在做什么,因为他们通常处理 MVC 而不是 Webforms。他们中的大多数人仍然使用 HttpContextBase
and/or HttpContextWrapper
但同样,我不确定如何实现它们。
此外 - 我没有直接测试 getText
方法。我知道它有效。我正在测试使用它的 class。在这种情况下嘲笑 HttpContext
会有帮助吗?
我确实意识到这是单元测试/集成测试的混合体,所以如果这不是最好的方法,我会洗耳恭听......或者.. 眼睛。
编辑
现在,如果 HttpContext.GetGlobalResourceObject
的结果为空,我将 getText
方法修改为 return 键(名称)。然后我更新了我的测试以期望键而不是值。这并不理想,但它有效并允许我继续。如果有更好的方法,请告诉我。
public static class MyStaticClass {
public static string getText(String name)
{
String s = HttpContext.GetGlobalResourceObject("MyResources", name);
return s != null ? s.ToString() : name;
}
}
带有假货的原始答案(请参阅下文以处理去除静电的问题)
所以有一个警告我完全忘记了,直到我尝试这样做。我很确定 Fakes 仍然需要 VS 的企业版。我不知道是否有办法让它与 NUnit 一起工作,但是当你无法更改代码时,有时你不得不处理它。
这是一个对静态方法进行 Shimming 的示例。您不必担心 HttpContext(目前),因为您没有直接使用它。相反,您可以调整 getText(string)
方法。
实际业务项目
namespace FakesExample
{
public class MyStaticClass
{
public static string GetText(string name)
{
throw new NullReferenceException();
}
}
}
你的单元测试项目
using System;
using Microsoft.QualityTools.Testing.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace FakesExampleTests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
using (ShimsContext.Create())
{
FakesExample.Fakes.ShimMyStaticClass.GetTextString = (s) =>
{
return "Go away null reference";
};
Console.WriteLine(FakesExample.MyStaticClass.GetText("foo"));
}
}
}
}
我实际上 运行 这个所以我知道它有效。发生的情况是,即使 GetText
在调用时总是抛出 NullReferenceException,我们的 Shim returns 我们自己的自定义消息。
您可能需要制作一个 Visual Studio 测试项目。
在您的单元测试项目中,右键单击您的引用并说 "Add Fakes"。它将为您的程序集生成所有垫片和存根。
去除静态的过程
最好的解决办法是真正努力消除静电。您已经找到了不使用它们的主要原因之一。
以下是我将如何删除静态和删除对 HttpContext 的依赖
public interface IResourceRepository
{
string Get(string name);
}
public class HttpContextResourceRepository : IResourceRepository
{
public string Get(string name)
{
return HttpContext.GetGlobalResourceObject("MyResources", name).ToString();
}
}
public class MyFormerStaticClass
{
IResourceRepository _resourceRepository;
public MyFormerStaticClass(IResourceRepository resourceRepository)
{
_resourceRepository = resourceRepository;
}
public string GetText(string name)
{
return _resourceRepository.Get(name);
}
}
然后我会利用依赖注入来处理在实际业务代码中创建我的 HttpContextResourceRepository
和 MyStaticClass
(可能也应该连接)。
对于单元测试,我会模拟实现
[TestFixture]
public class UnitTest1
{
[Test]
public void TestMethod1()
{
var repoMock = new Mock<IResourceRepository>();
repoMock.Setup(repository => repository.Get("foo")).Returns("My Resource Value");
var formerStatic = new MyFormerStaticClass(repoMock.Object);
Console.WriteLine(formerStatic.GetText("foo"));
}
}
按照这条路线,您可以创建任意数量的 IResourceRepository 实现并随时交换它们。
我正在尝试向 webforms 项目添加测试。有一个静态方法可以从资源文件中获取行。我正在尝试测试的 classes 之一依赖于从资源文件中抓取文本。
public static class MyStaticClass {
public static string getText(String name)
{
String s = HttpContext.GetGlobalResourceObject("MyResources", name).ToString();
return s;
}
}
public class ClassUnderTest
{
// returns: "Hey it's my text"
private string _eg = MyStaticClass.getText("label_in_resources.resx_file")
}
class UnitTests
{
[Test]
public void TestMyClass()
{
ClassUnderTest _cut = new ClassUnderTest();
// errors out because ClassUnderTest utilizes getText
// which requires HttpContext.GetGlobalResourceObject
// ... other stuff
}
}
注意:这些是简单的示例。
问题是我收到测试失败消息:
Message: System.NullReferenceException : Object reference not set to an instance of an object.
根据我的调查,我确定这是因为 HttpContext
在这些测试期间为空。
我看过很多关于模拟的 SO 帖子 HttpContext
但我不认为我完全理解他们到底在做什么,因为他们通常处理 MVC 而不是 Webforms。他们中的大多数人仍然使用 HttpContextBase
and/or HttpContextWrapper
但同样,我不确定如何实现它们。
此外 - 我没有直接测试 getText
方法。我知道它有效。我正在测试使用它的 class。在这种情况下嘲笑 HttpContext
会有帮助吗?
我确实意识到这是单元测试/集成测试的混合体,所以如果这不是最好的方法,我会洗耳恭听......或者.. 眼睛。
编辑
现在,如果 HttpContext.GetGlobalResourceObject
的结果为空,我将 getText
方法修改为 return 键(名称)。然后我更新了我的测试以期望键而不是值。这并不理想,但它有效并允许我继续。如果有更好的方法,请告诉我。
public static class MyStaticClass {
public static string getText(String name)
{
String s = HttpContext.GetGlobalResourceObject("MyResources", name);
return s != null ? s.ToString() : name;
}
}
带有假货的原始答案(请参阅下文以处理去除静电的问题)
所以有一个警告我完全忘记了,直到我尝试这样做。我很确定 Fakes 仍然需要 VS 的企业版。我不知道是否有办法让它与 NUnit 一起工作,但是当你无法更改代码时,有时你不得不处理它。
这是一个对静态方法进行 Shimming 的示例。您不必担心 HttpContext(目前),因为您没有直接使用它。相反,您可以调整 getText(string)
方法。
实际业务项目
namespace FakesExample
{
public class MyStaticClass
{
public static string GetText(string name)
{
throw new NullReferenceException();
}
}
}
你的单元测试项目
using System;
using Microsoft.QualityTools.Testing.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace FakesExampleTests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
using (ShimsContext.Create())
{
FakesExample.Fakes.ShimMyStaticClass.GetTextString = (s) =>
{
return "Go away null reference";
};
Console.WriteLine(FakesExample.MyStaticClass.GetText("foo"));
}
}
}
}
我实际上 运行 这个所以我知道它有效。发生的情况是,即使 GetText
在调用时总是抛出 NullReferenceException,我们的 Shim returns 我们自己的自定义消息。
您可能需要制作一个 Visual Studio 测试项目。
在您的单元测试项目中,右键单击您的引用并说 "Add Fakes"。它将为您的程序集生成所有垫片和存根。
去除静态的过程
最好的解决办法是真正努力消除静电。您已经找到了不使用它们的主要原因之一。
以下是我将如何删除静态和删除对 HttpContext 的依赖
public interface IResourceRepository
{
string Get(string name);
}
public class HttpContextResourceRepository : IResourceRepository
{
public string Get(string name)
{
return HttpContext.GetGlobalResourceObject("MyResources", name).ToString();
}
}
public class MyFormerStaticClass
{
IResourceRepository _resourceRepository;
public MyFormerStaticClass(IResourceRepository resourceRepository)
{
_resourceRepository = resourceRepository;
}
public string GetText(string name)
{
return _resourceRepository.Get(name);
}
}
然后我会利用依赖注入来处理在实际业务代码中创建我的 HttpContextResourceRepository
和 MyStaticClass
(可能也应该连接)。
对于单元测试,我会模拟实现
[TestFixture]
public class UnitTest1
{
[Test]
public void TestMethod1()
{
var repoMock = new Mock<IResourceRepository>();
repoMock.Setup(repository => repository.Get("foo")).Returns("My Resource Value");
var formerStatic = new MyFormerStaticClass(repoMock.Object);
Console.WriteLine(formerStatic.GetText("foo"));
}
}
按照这条路线,您可以创建任意数量的 IResourceRepository 实现并随时交换它们。