You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为服务中的UpdateCookiesAccordingToConsent方法编写xUnit测试?

使用xUnit测试UpdateCookiesAccordingToConsent方法

核心测试场景

要覆盖该方法的所有逻辑分支,需针对以下场景编写测试:

  • 传入的Cookie名称不在_httpOnlyCookies字典中,不执行移除操作
  • 传入的Cookie名称在字典中,但用户已同意该类Cookie,不执行移除操作
  • 传入的Cookie名称在字典中,且用户未同意该类Cookie,执行移除操作

依赖模拟准备

使用Moq框架模拟IHttpContextAccessor和ILogger<YourService>(替换YourService为实际服务类名),同时自定义MockResponseCookies类捕获Cookie移除操作的执行情况。

完整测试代码

using Xunit;
using Moq;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;

public class YourServiceTests
{
    private readonly Mock<IHttpContextAccessor> _httpContextAccessorMock;
    private readonly Mock<ILogger<YourService>> _loggerMock;
    private readonly YourService _service;

    public YourServiceTests()
    {
        _httpContextAccessorMock = new Mock<IHttpContextAccessor>();
        _loggerMock = new Mock<ILogger<YourService>>();
        _service = new YourService(_httpContextAccessorMock.Object, _loggerMock.Object);
    }

    [Fact]
    public void UpdateCookiesAccordingToConsent_CookieNotInDictionary_DoesNotRemove()
    {
        // 准备:传入不存在的Cookie,设置任意同意状态
        var nonExistentCookie = "UnknownCookie";
        SetupHttpContextWithConsent(new CookieConsent { Statistics = false });

        // 执行方法
        _service.UpdateCookiesAccordingToConsent(nonExistentCookie);

        // 验证:未执行Cookie移除操作
        var responseCookies = GetMockResponseCookies();
        Assert.Empty(responseCookies.AppendedCookies);
    }

    [Fact]
    public void UpdateCookiesAccordingToConsent_CookieExistsWithConsent_DoesNotRemove()
    {
        // 准备:传入存在的统计类Cookie,设置用户已同意
        var targetCookie = CookieNames.VisitorCookieName;
        SetupHttpContextWithConsent(new CookieConsent { Statistics = true });

        // 执行方法
        _service.UpdateCookiesAccordingToConsent(targetCookie);

        // 验证:未执行Cookie移除操作
        var responseCookies = GetMockResponseCookies();
        Assert.Empty(responseCookies.AppendedCookies);
    }

    [Fact]
    public void UpdateCookiesAccordingToConsent_CookieExistsWithoutConsent_RemovesCookie()
    {
        // 准备:传入存在的统计类Cookie,设置用户未同意
        var targetCookie = CookieNames.VisitorCookieName;
        var consent = new CookieConsent { Statistics = false };
        var responseCookies = new MockResponseCookies();
        var httpContext = new DefaultHttpContext
        {
            Request = { Cookies = new RequestCookieCollection(new Dictionary<string, string> 
                { { "CookieConsent", JsonConvert.SerializeObject(consent) } }) },
            Response = { Cookies = responseCookies }
        };
        _httpContextAccessorMock.Setup(x => x.HttpContext).Returns(httpContext);

        // 执行方法
        _service.UpdateCookiesAccordingToConsent(targetCookie);

        // 验证:正确执行移除操作
        Assert.Single(responseCookies.AppendedCookies);
        var appended = responseCookies.AppendedCookies.First();
        Assert.Equal(targetCookie, appended.Key);
        Assert.Equal(string.Empty, appended.Value);
        Assert.True(appended.Options.HttpOnly);
        Assert.Equal(DateTime.Now.AddDays(-1).Date, appended.Options.Expires?.Date);
    }

    private void SetupHttpContextWithConsent(CookieConsent consent)
    {
        var consentJson = JsonConvert.SerializeObject(consent);
        var httpContext = new DefaultHttpContext
        {
            Request = { Cookies = new RequestCookieCollection(new Dictionary<string, string> 
                { { "CookieConsent", consentJson } }) },
            Response = { Cookies = new MockResponseCookies() }
        };
        _httpContextAccessorMock.Setup(x => x.HttpContext).Returns(httpContext);
    }

    private MockResponseCookies GetMockResponseCookies()
    {
        return _httpContextAccessorMock.Object.HttpContext.Response.Cookies as MockResponseCookies;
    }
}

// 自定义类:捕获Response.Cookies的Append操作
public class MockResponseCookies : IResponseCookies
{
    public List<(string Key, string Value, CookieOptions Options)> AppendedCookies { get; } = new();

    public void Append(string key, string value) => AppendedCookies.Add((key, value, new CookieOptions()));
    public void Append(string key, string value, CookieOptions options) => AppendedCookies.Add((key, value, options));
    public void Delete(string key) { }
    public void Delete(string key, CookieOptions options) { }
}

// 需与项目中实际类结构一致
public class CookieConsent
{
    public bool Preferences { get; set; }
    public bool Marketing { get; set; }
    public bool Statistics { get; set; }
    public bool Necessary { get; set; }
}

public static class CookieNames
{
    public const string VisitorCookieName = "VisitorCookie";
    public const string GoogleAnalyticsTrackingCookieName = "GATrackingCookie";
    public const string TaxonomyVisitorCookieName = "TaxonomyVisitorCookie";
    public const string MarketoMunchkinTrackingCookieName = "MarketoMunchkinCookie";
}

public enum CookiesConsentType
{
    Preferences,
    Marketing,
    Statistic,
    Necessary
}

关键说明

  1. 控制HasCookieConsent返回值:通过在DefaultHttpContext的Request中设置CookieConsent的JSON值,间接控制私有方法HasCookieConsent的返回结果,无需反射调用私有方法。
  2. 验证移除操作:通过MockResponseCookies记录Response.Cookies.Append的调用参数,验证Remove方法是否正确设置了过期Cookie。
  3. 分支覆盖:三个测试用例完整覆盖了方法的所有逻辑分支,确保方法行为符合预期。

内容的提问来源于stack exchange,提问作者cowefe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 02:05:22