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

如何在Xamarin Forms中使用NUnit对网络连接功能进行单元测试

Xamarin.Forms网络检测逻辑的NUnit单元测试实现

你当前的代码直接依赖Xamarin.Essentials的静态Connectivity类,静态依赖无法在单元测试中灵活控制返回值,没法隔离外部系统状态做独立测试,所以先做最小化的可测试性改造,再写用例即可。

前置改造:解耦静态依赖

不要在业务逻辑里直接调用静态Connectivity,先抽一层薄抽象把静态调用包装起来,既不影响生产逻辑,也能方便测试时模拟不同网络状态:

// 抽离网络状态访问的抽象
public interface IConnectivityService
{
    NetworkAccess CurrentNetworkAccess { get; }
}

// 生产环境实现,直接包装Xamarin.Essentials的静态调用
public class XamarinEssentialsConnectivityService : IConnectivityService
{
    public NetworkAccess CurrentNetworkAccess => Connectivity.NetworkAccess;
}

再改造原有的InternetConnection类,通过构造函数注入抽象,同时把硬编码的2秒重检延迟做成可配置参数——测试时可以传极小的延迟值,避免每次测试等2秒拖慢执行速度:

public class InternetConnection : IInternetConnection
{
    private readonly IConnectivityService _connectivityService;
    private readonly int _recheckDelayMilliseconds;

    public InternetConnection(IConnectivityService connectivityService, int recheckDelayMilliseconds = 2000)
    {
        _connectivityService = connectivityService;
        _recheckDelayMilliseconds = recheckDelayMilliseconds;
    }

    public async Task<bool> CheckInternetStatusAsync()
    {
        if (_connectivityService.CurrentNetworkAccess != NetworkAccess.Internet)
        {
            // 延迟重检处理公共场所网络瞬断
            await Task.Delay(_recheckDelayMilliseconds);
            if (_connectivityService.CurrentNetworkAccess != NetworkAccess.Internet)
            {
                return false;
            }
        }
        return true;
    }
}

生产环境使用时,注入XamarinEssentialsConnectivityService实例即可,原有业务逻辑完全不受影响。

NUnit测试用例编写

你可以用Moq这类Mock框架模拟IConnectivityService的返回值,覆盖全部3个核心逻辑分支:

  • 首次检测即联网,直接返回true,不触发延迟等待
  • 首次检测断网,等待重检时网络恢复(对应瞬断场景),返回true
  • 两次检测都断网,返回false

测试代码如下:

using Moq;
using NUnit.Framework;

[TestFixture]
public class InternetConnectionTests
{
    [Test]
    public async Task CheckInternetStatusAsync_FirstCheckHasInternet_ReturnsTrueWithoutWait()
    {
        // 安排测试上下文
        var mockConnectivity = new Mock<IConnectivityService>();
        mockConnectivity.Setup(c => c.CurrentNetworkAccess).Returns(NetworkAccess.Internet);
        const int testDelay = 10; // 测试场景用极短延迟,避免拖慢测试
        var testInstance = new InternetConnection(mockConnectivity.Object, testDelay);
        var startTime = DateTime.UtcNow;

        // 执行测试方法
        var result = await testInstance.CheckInternetStatusAsync();
        var timeCost = (DateTime.UtcNow - startTime).TotalMilliseconds;

        // 断言结果
        Assert.IsTrue(result);
        Assert.Less(timeCost, testDelay); // 验证没有走到延迟重检分支
    }

    [Test]
    public async Task CheckInternetStatusAsync_BlipRecovered_ReturnsTrue()
    {
        // 安排测试上下文:第一次调用返回断网,第二次返回联网,模拟瞬断恢复
        var mockConnectivity = new Mock<IConnectivityService>();
        var callCount = 0;
        mockConnectivity.Setup(c => c.CurrentNetworkAccess)
            .Returns(() => callCount++ == 0 ? NetworkAccess.None : NetworkAccess.Internet);
        const int testDelay = 10;
        var testInstance = new InternetConnection(mockConnectivity.Object, testDelay);

        // 执行测试方法
        var result = await testInstance.CheckInternetStatusAsync();

        // 断言结果
        Assert.IsTrue(result);
        mockConnectivity.Verify(c => c.CurrentNetworkAccess, Times.Exactly(2)); // 验证确实触发了重检
    }

    [Test]
    public async Task CheckInternetStatusAsync_NoNetworkAfterRecheck_ReturnsFalse()
    {
        // 安排测试上下文:始终返回断网
        var mockConnectivity = new Mock<IConnectivityService>();
        mockConnectivity.Setup(c => c.CurrentNetworkAccess).Returns(NetworkAccess.None);
        const int testDelay = 10;
        var testInstance = new InternetConnection(mockConnectivity.Object, testDelay);

        // 执行测试方法
        var result = await testInstance.CheckInternetStatusAsync();

        // 断言结果
        Assert.IsFalse(result);
        mockConnectivity.Verify(c => c.CurrentNetworkAccess, Times.Exactly(2));
    }
}

补充说明

  • 如果不想引入Moq依赖,也可以自己写个简单的测试桩类实现IConnectivityService,手动控制CurrentNetworkAccess的返回值,测试效果完全一致
  • 异步测试方法必须返回Task,不要写async void,否则NUnit无法正确捕获测试执行过程中的异常
  • 生产环境注入InternetConnection时不用传延迟参数,默认就是你需要的2秒重检间隔

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 21:30:53