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

DotNet MAUI 7中IDispatcherTimer注入致单元测试编译失败

问题描述

我在MAUI 7应用中使用Microsoft依赖注入,此前构造注入和单元测试都正常。但注入IDispatcherTimer相关接口后,应用可以正常运行,单元测试却编译失败,错误提示需要引用Microsoft.Maui程序集。我认为单元测试项目不应该依赖.NET MAUI。

单元测试编译错误信息

Severity    Code    Description Project File    Line    Suppression State
Error   CS0012  The type 'IDispatcherTimer' is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. MineSweeperTests    C:\Users\markwardell\source\repos\MineSweeper\MineSweeperTests\ViewModels\SweeperViewModel-Tests.cs 28  Active

相关代码

被测ViewModel构造函数

public SweeperViewModel(ILogger<SweeperViewModel> logger, IGameBoardViewModel gameBoard, IDispatcherTimer dispatchTimer)
{
   _logger = logger;
   _gameBoard = gameBoard;
   _timer = dispatchTimer;   
}

GameTimer实现类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MineSweeper.Models
{
   public class GameTimer : IGameTimer
   {
      IDispatcherTimer _timer;
      public GameTimer()
      {
         _timer = Application.Current.Dispatcher.CreateTimer();
      }
      public TimeSpan Interval {  get => _timer.Interval; set => _timer.Interval = value; }
      public bool IsRepeating {  get => _timer.IsRepeating; set => _timer.IsRepeating = value; }

      public bool IsRunning => _timer.IsRunning;

      public event EventHandler Tick;

      public void Start()
      {
         _timer.Start();
      }

      public void Stop()
      {
         _timer.Stop();      
      }
   }
}

IGameTimer接口(与Microsoft.Maui.Dispatching.IDispatcherTimer完全一致但独立)

namespace MineSweeper.Models
{
   public interface IGameTimer
   {
      public TimeSpan Interval { get; set; }
      public bool IsRepeating { get; set; }

      public bool IsRunning { get; }

      public event EventHandler Tick;

      public void Start();

      public void Stop();
   }
}
解决方案

问题核心是ViewModel构造函数直接依赖了MAUI的IDispatcherTimer接口,这个类型属于Microsoft.Maui程序集,而单元测试项目没有引用该程序集,导致编译报错。你已经定义了独立的IGameTimer接口,完全可以用它来解耦ViewModel与MAUI的依赖。

具体修改步骤:

  1. 修改ViewModel构造函数,将参数类型从IDispatcherTimer替换为自定义的IGameTimer:
public SweeperViewModel(ILogger<SweeperViewModel> logger, IGameBoardViewModel gameBoard, IGameTimer gameTimer)
{
   _logger = logger;
   _gameBoard = gameBoard;
   _timer = gameTimer;   
}
  1. 在MAUI应用的DI容器中注册依赖:
builder.Services.AddSingleton<IGameTimer, GameTimer>();
  1. 单元测试时使用Mock实现:
    用Moq等框架创建IGameTimer的Mock实例,完全不需要依赖MAUI程序集,示例如下:
var mockTimer = new Mock<IGameTimer>();
// 根据测试需求设置Mock行为,比如模拟Tick触发、验证Start/Stop调用等
var viewModel = new SweeperViewModel(mockLogger.Object, mockGameBoard.Object, mockTimer.Object);

修改后,ViewModel不再直接依赖MAUI特定类型,单元测试项目无需引用Microsoft.Maui,同时应用端的功能不受影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 16:05:09