繁体   English   中英

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

[英]How do I unit test a class that relies on HttpContext.GetGlobalResourceObject?

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

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
    }
}

注意:这些是简单的例子。

问题是我得到一个测试失败的消息:

消息:System.NullReferenceException:未将对象引用设置为对象的实例。

通过我的调查,我确定这是因为在这些测试期间HttpContext为null。

我看过很多关于模仿HttpContext帖子,但我不认为我完全理解他们究竟在做什么,因为他们通常处理MVC而不是Webforms。 他们中的大多数仍然使用HttpContextBase和/或HttpContextWrapper但是我再也不知道如何实现它们。

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

我确实意识到这是一种单元测试/集成测试的混合体,所以如果这不是最好的方式,我会全神贯注......或者......而是眼睛。

编辑

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

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(还),因为你没有直接使用它。 相反,你可以Shim你的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测试项目。

在单元测试项目中,右键单击您的引用并说“添加假”。 它将为您的装配生成所有垫片和短柱。


去除静电的过程

最好的解决方案是实际去除静电。 你已经找到了不使用它们的一个主要原因。

这是我如何去除静态和删除对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);
    }
}

然后,我将利用依赖注入来处理在实际业务代码中创建我的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实现并随时交换它们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM