【问题标题】:How to bypass (custom) MessageBoxes when unit testing with Moq?使用 Moq 进行单元测试时如何绕过(自定义)消息框?
【发布时间】:2021-10-24 19:03:51
【问题描述】:

更新:

添加了请求的表格绘制代码,调用 MessageBoxService.Show()。

/// <summary>
    /// Draws the classic sudoku table with the given size.
    /// </summary>
    protected override void Draw(object o)
    {
        if (GetCurrentTableViewModel() != null && GetCurrentTableViewModel().AreAnyCellsFilled())
        {
            var messageBoxResult = MessageBoxService.Show(
               Resources.MessageBox_DrawIfNumbersArePresented,
               Resources.MessageBox_Question_Title, MessageBoxButton.YesNo, MessageBoxImage.Question);

            if (messageBoxResult == MessageBoxResult.No || messageBoxResult == MessageBoxResult.Cancel)
            {
                return;
            }
        }

        SudokuBoardSize sudokuBoardSize = (SudokuBoardSize)o;

        bool oldDiagonalRulesStatus = AreDiagonalRulesApplied;
        if (sudokuBoardSize.Height == 9 && sudokuBoardSize.Width == 9)
        {
            SudokuBoardControl = new UcClassicSudoku9x9Table();
            _actualSudokuBoard = CreateBoard(sudokuBoardSize, (BaseSudokuTableViewModel)SudokuBoardControl.DataContext, false);
        }
        else if (sudokuBoardSize.Height == 6 && sudokuBoardSize.Width == 6)
        {
            SudokuBoardControl = new UcClassicSudoku6x6Table();
            _actualSudokuBoard = CreateBoard(sudokuBoardSize, (BaseSudokuTableViewModel)SudokuBoardControl.DataContext, false);
        }
        else
        {
            SudokuBoardControl = new UcClassicSudoku4x4Table();
            _actualSudokuBoard = CreateBoard(sudokuBoardSize, (BaseSudokuTableViewModel)SudokuBoardControl.DataContext, false);
        }

        ((BaseClassicSudokuTableViewModel)SudokuBoardControl.DataContext).AreDiagonalRulesApplied = oldDiagonalRulesStatus;
        SolutionCounter = string.Empty;
        IsSolutionCounterVisible = false;
        _solutions.Clear();
    }

我是 Stackoverflow 的新手,如有任何错误,我深表歉意。

我开发了一个数独求解器爱好项目,我想向其中添加单元测试。它完全是 MVVM。 (https://github.com/denesdavid/Solvedoku)

当当前数独中至少有一个填充单元格时,我想测试“绘制新的空表”功能。在这种情况下,软件会询问您是否真的要画一个新的。我想绕过这个问题,我的意思是......模拟按下是按钮。我读到起订量非常适合这个,但它目前不适合我。在单元测试期间会弹出问题,但我必须手动单击“是”。

这是我的测试:

[TestMethod]
    public void Draw9x9TableWithAlreadyFilledCellsTest()
    {
        Mock<IMessageBoxService> messageBoxMock = new Mock<IMessageBoxService>(MockBehavior.Strict);
        messageBoxMock.Setup(m =>
            m.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxButton>(),
            It.IsAny<MessageBoxImage>()));
        messageBoxMock.SetReturnsDefault(MessageBoxResult.OK);
        
        ClassicSudokuViewModel classicSudokuViewModel = new ClassicSudokuViewModel(messageBoxMock.Object);
        SudokuBoardSize sudokuBoardSize = new SudokuBoardSize();
        sudokuBoardSize.Height = 9;
        sudokuBoardSize.Width = 9;
        sudokuBoardSize.BoxCountX = 3;
        sudokuBoardSize.BoxCountY = 3;

        
        BaseSudokuTableViewModel tableViewModel = classicSudokuViewModel.GetCurrentTableViewModel();
        tableViewModel.Cells[0][0] = "1";
        classicSudokuViewModel.DrawSudokuCommand.Execute(sudokuBoardSize);
        object actualBoard = classicSudokuViewModel.SudokuBoardControl;
        tableViewModel = classicSudokuViewModel.GetCurrentTableViewModel();

        Assert.AreEqual(typeof(UcClassicSudoku9x9Table), actualBoard.GetType());
        Assert.AreEqual(string.Empty, tableViewModel.Cells[0][0]);
        Assert.AreEqual(false, classicSudokuViewModel.AreDiagonalRulesApplied);
        Assert.AreEqual(string.Empty, classicSudokuViewModel.SolutionCounter);
        Assert.AreEqual(false, classicSudokuViewModel.IsSolutionCounterVisible);
        Assert.AreEqual(0, classicSudokuViewModel.Solutions.Count);
    }

IMessageBox 服务:

public interface IMessageBoxService
{
    /// <summary>
    /// Shows a MessageBox with the given text, title, button(s) and image.
    /// </summary>
    /// <param name="messageText">Text of the MessageBox.</param>
    /// <param name="title">Title of the MessageBox</param>
    /// <param name="messageBoxButton">Button(s) of the MessageBox</param>
    /// <param name="messageBoxImage">Image of the MessageBox</param>
    /// <returns>MessageBoxResult</returns>
    MessageBoxResult Show(string messageText, string title, MessageBoxButton messageBoxButton,
        MessageBoxImage messageBoxImage);

    /// <summary>
    /// Shows a MessageBox with the given text, title, button(s), image and style.
    /// </summary>
    /// <param name="messageText">Text of the MessageBox.</param>
    /// <param name="title">Title of the MessageBox</param>
    /// <param name="messageBoxButton">Button(s) of the MessageBox</param>
    /// <param name="messageBoxImage">Image of the MessageBox</param>
    /// <param name="messageBoxStyle">Style of the MessageBox</param>
    /// <returns>MessageBoxResult</returns>
    MessageBoxResult Show(string messageText, string title, MessageBoxButton messageBoxButton,
        MessageBoxImage messageBoxImage, Style messageBoxStyle);
}

}

消息框服务:

class MessageBoxService : DependencyObject, IMessageBoxService
{
    private Style _messageBoxStyle = (Style)Application.Current?.Resources["MessageBoxStyle"];

    /// <summary>
    /// Displays a messagebox with the given parameters.
    /// </summary>
    /// <param name="messageText">Text of the messagebox.</param>
    /// <param name="title">Title of the messagebox.</param>
    /// <param name="messageBoxButton">Displayed button(s) in the messagebox. (Choose from the MessageBoxButton enum.).</param>
    /// <param name="messageBoxImage">Displayed icon in the messagebox. (Choose from the MessageBoxImage enum.).</param>
    /// <returns>MessageBoxResult</returns>
    public MessageBoxResult Show(string messageText, string title, MessageBoxButton messageBoxButton, MessageBoxImage messageBoxImage)
    {
        return Xceed.Wpf.Toolkit.MessageBox.Show(Application.Current?.MainWindow, messageText, title, messageBoxButton, messageBoxImage, _messageBoxStyle);
    }

    /// <summary>
    /// Displays a messagebox with the given parameters.
    /// </summary>
    /// <param name="messageText">Text of the messagebox.</param>
    /// <param name="title">Title of the messagebox.</param>
    /// <param name="messageBoxButton">Displayed button(s) in the messagebox. (Choose from the MessageBoxButton enum.).</param>
    /// <param name="messageBoxImage">Displayed icon in the messagebox. (Choose from the MessageBoxImage enum.).</param>
    /// <param name="messageBoxStyle">Style what is applied on the MessageBox.</param>
    /// <returns>MessageBoxResult</returns>
    public MessageBoxResult Show(string messageText, string title, MessageBoxButton messageBoxButton, MessageBoxImage messageBoxImage, Style messageBoxStyle)
    {
        return Xceed.Wpf.Toolkit.MessageBox.Show(Application.Current?.MainWindow, messageText, title, messageBoxButton, messageBoxImage, messageBoxStyle);
    }
}

}

感谢您的帮助!

【问题讨论】:

  • 接口有两种方法,一定要mock正确的一种。
  • 你能显示ClassicSudokuViewModel吗?特别是被称为Show的部分。
  • @vernou 我已将其添加到帖子中。
  • 你能调试测试并检查属性MessageBoxService是模拟吗?
  • 模拟似乎是正确的。我还创建了一个完全独立的项目和解决方案,并且消息框模拟在那里工作就像一个魅力。我真的不明白这里发生了什么。

标签: c# unit-testing mocking moq messagebox


【解决方案1】:

问题解决了。

感谢@vernou 的时间和帮助。问题出在 BaseSudokuTableViewModel 类中,它被称为 ViewModelBase 类,带有一个全新的 MessageBoxService 实例,所以不是模拟的,所以它覆盖了模拟。

我知道这是一个平庸的错误,但我现在因为工作而感到疲倦。

再次非常感谢您!

【讨论】:

    猜你喜欢
    • 2010-11-08
    • 1970-01-01
    • 2018-03-29
    • 1970-01-01
    • 2011-12-24
    • 2011-01-30
    • 2012-10-19
    • 1970-01-01
    相关资源
    最近更新 更多