c# - 如何对依赖于 HttpContext.GetGlobalResourceObject 的类进行单元测试?

标签 c# unit-testing webforms nunit-3.0

我正在尝试向网络表单项目添加测试。有一个静态方法可以从资源文件中获取行。我正在尝试测试的其中一个类依赖于从资源文件中获取文本。

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 为 null。

我看过很多关于模拟 HttpContext 的 SO 帖子,但我不认为我完全理解他们到底在做什么,因为他们通常处理 MVC 而不是 Webforms .他们中的大多数仍然使用 HttpContextBase 和/或 HttpContextWrapper 但同样,我不确定如何实现它们。

另外 - 我没有直接测试 getText 方法。我知道它有效。我正在测试一个使用它的类。在这种情况下模拟 HttpContext 会有帮助吗?

我确实意识到这是单元测试/集成测试的混合体,所以如果这不是最好的方法,我会洗耳恭听......或者.. 眼睛。

编辑

现在,我修改了我的 getText 方法以在 HttpContext.GetGlobalResourceObject 的结果为 null 时返回键(名称)。然后我更新了我的测试以期望键而不是值。这并不理想,但它有效并允许我继续。如果有更好的方法,请告诉我。

public static class MyStaticClass {
    public static string getText(String name)
    {
        String s = HttpContext.GetGlobalResourceObject("MyResources", name);
        return s != null ? s.ToString() : name;
    }
}

最佳答案

带有 Fakes 的原始答案(请参阅下文了解如何处理去除静电)

所以有一个警告我完全忘记了,直到我尝试这样做。我很确定 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 也会返回我们自己的自定义消息。

您可能必须制作一个 Visual Studio 测试项目。

在您的单元测试项目中,右键单击您的引用并说“添加假货”。它将为您的程序集生成所有垫片和 stub 。


去除静电的过程

最好的解决方案是真正努力消除静电。您已经找到了不使用它们的主要原因之一。

下面是我将如何删除静态并删除对 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);
    }
}

然后我会利用依赖注入(inject)来处理在实际业务代码中创建我的 HttpContextResourceRepositoryMyStaticClass(可能也应该连接)。

对于单元测试,我会模拟实现

[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 实现并在需要时交换它们。

关于c# - 如何对依赖于 HttpContext.GetGlobalResourceObject 的类进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50724561/

相关文章:

c# - Asp.Net Core 2.1 ApiController 不会自动验证单元测试下的模型

c# - 一种在 ASP.NET 中的每个页面中来回传递参数的简单方法

c# - 新手需要帮助: Server Error

c# - 如何防止在 ASP.Net Web Forms (Identity) 中注册后自动登录?

进程的 C#.NET 监控

c# - 如何在 ASP .NET Core 中生成和管理 API key

c# - C#中是否有方法继承

c# - 测试 HttpResponse.StatusCode 的结果

c# - 是否可以在运行时向现有类添加方法?为什么或者为什么不?

angular - 如何在 Angular 单元测试中使用模拟打开 MatDialog