2017-08-25 53 views
1

我在WPF編寫單元測試與起訂量來測試用戶是否點擊了一個YesNoCancel MessageBox中的「是」按鈕時,他們關閉窗戶。在我CloseCommand我在我的視圖模型給出了當用戶關閉窗口下面的消息:以下設置不匹配,WPF MVVM單元測試與起訂量

var result = _messageSvc.Show(
    "Do you want to save changes?", 
    "Save Changes", 
    Services.MessageBoxButton.YesNoCancel, 
    Services.MessageBoxIcon.Question, 
    Services.MessageBoxResult.Yes); 

_messageSvc是一個自定義郵件服務以顯示消息框內部的私有實例。下面是服務的代碼:

public interface IMessageSvc 
{ 
    void Show(string message); 
    MessageBoxResult Show(string message, string caption, MessageBoxButton buttons, MessageBoxIcon icon, MessageBoxResult defaultResult = 0); 
} 

public class MessageSvc : IMessageSvc 
{ 
    public void Show(string message) 
    { 
     MessageBox.Show(message); 
    } 

    public MessageBoxResult Show(string message, string caption, MessageBoxButton buttons, MessageBoxIcon icon, MessageBoxResult defaultResult) 
    { 
     return (MessageBoxResult)MessageBox.Show(message, caption, (System.Windows.MessageBoxButton)buttons, (System.Windows.MessageBoxImage)icon, (System.Windows.MessageBoxResult)defaultResult); 
    } 
} 

注:MessageBoxButtonMessageBoxIcon,並MessageBoxResult是枚舉我在同一個文件進行模仿什麼.NET提供開箱即用的。我不向他們展示這裏的可讀性

我的單元測試的緣故:

[TestMethod] 
public void ShouldAskToSaveOnCloseRespondYesTest() 
{ 
    // Mock and setup initial user data 
    var u= new User 
    { 
     UserId = 1, 
     UserName = "FirstName LastName", 
     FavoriteColor = "Blue" 
    }; 
    mainViewModel.UserInfo= new UserInfoDtoWrapper(u); 

    // assert the data has not changed yet 
    Assert.IsFalse(mainViewModel.UserInfo.IsChanged); 

    // change the user data 
    mainViewModel.UserInfo.UserName= "LastName FirstName"; 

    // assert the data has changed 
    Assert.IsTrue(mainViewModel.UserInfo.IsChanged); 

    // execute window closing 
    mainViewModel.CloseCommand.Execute(new object()); 

    // verify messagebox shows and the 'Yes' button is clicked 
    // this will then save the changes made to the user instance 
    var messageBox = new Mock<IMessageSvc>(); 
    messageBox.Setup(x => x.Show(It.Is<string>(y => y == "Do you want to save changes?"), 
     It.Is<string>(y => y == "Save Changes"), 
     It.Is<MessageBoxButton>(y => y == MessageBoxButton.YesNoCancel), 
     It.Is<MessageBoxIcon>(y => y == MessageBoxIcon.Question), 
     It.Is<MessageBoxResult>(y => y == MessageBoxResult.Yes))) 
     .Returns(MessageBoxResult.Yes); 

    messageBox.Verify(); 
} 

的錯誤出現在messageBox.Verify()線,但是從我所看到的,我做正確。我需要獲取消息框的返回值,以繼續測試用戶單擊「是」按鈕後發生的情況,所以我不想在內部使用帶有Linq查詢的Verify,而是需要捕獲結果。

謝謝

+0

「錯誤發生在messageBox.Verify()行」 - 什麼錯誤? –

+0

ShouldAskToSaveOnCloseRespondYesTest引發異常:Moq.MockVerificationException:以下設置不匹配:IMessageSvc x => x.Show(它是(y => y ==「您是否想保存更改嗎?」),它是。 (y => y ==「保存更改」)... –

+0

安裝和驗證之間的其餘代碼在哪裏?目前沒有測試執行 –

回答

2

這是行不通的。你在你的測試代碼2個問題:

  1. 你先火CloseCommand(假定調用IMessageSvc.Show方法),然後才安裝了該服務的模擬。

  2. 您爲服務設置了一個新的模擬,但不使用它。

要糾正這些錯誤:

  • 更改順序,這是一個正確的「安排」 - 「行動」 - 「斷言」爲了
  • 注入你的嘲笑服務視圖模型使用依賴注入

下面是一個例子:

class MainViewModel 
{ 
    private readonly IMessageSvc _messageSvc; 

    public MainViewModel(IMessageSvc svc) 
    { 
     this._messageSvc = svc; 
    } 
} 

[TestMethod] 
public void ShouldAskToSaveOnCloseRespondYesTest() 
{ 
    // Arrange 
    var messageBox = new Mock<IMessageSvc>(); 
    messageBox.Setup(x => x.Show(It.Is<string>(y => y == "Do you want to save changes?"), 
     It.Is<string>(y => y == "Save Changes"), 
     It.Is<MessageBoxButton>(y => y == MessageBoxButton.YesNoCancel), 
     It.Is<MessageBoxIcon>(y => y == MessageBoxIcon.Question), 
     It.Is<MessageBoxResult>(y => y == MessageBoxResult.Yes))) 
     .Returns(MessageBoxResult.Yes) 
     .Verifiable(); 

    var mainViewModel = new MainViewModel(messageBox.Object); 

    // Act 
    mainViewModel.CloseCommand.Execute(new object()); 

    // Assert 
    messageBox.Verify(); 
} 
+0

我將消息服務對象添加到單元測試類初始化的視圖模型構造函數,以便從那裏注入。然而,在單元測試方法中,在將我的代碼按照您展示的方式排列後,我仍然得到相同的錯誤。 –

+0

@ J-man,不,你沒有按照我的建議安排你的代碼。您正在測試方法中爲您的服務創建一個新的模擬。這個模擬的服務必須提供給視圖模型。您必須在測試方法中創建視圖模型(如我所建議的那樣),或者在創建視圖模型的類初始化中設置服務模擬。 – dymanoid

+0

你是對的@dymanoid,當我已經有權訪問在單元測試類的初始化方法中注入的類作用域messageSvc對象時,我錯誤地設置了一個新的我的消息服務的模擬實例。所以我應該設置'messageSvc.Setup(...)'而不是我正在做的'var messageBox = new Mock (); messageBox.Setup(...)'。難怪無法找到正確的設置,因爲SAME對象需要注入虛擬機,所以我錯誤地試圖注入一個新對象。謝謝!!我會將你的標記作爲答案。 –

0

當前你正在設置你的模擬方法測試將調用它的代碼。重新安排您的測試AAA (Arrange, Act, Assert)模式像這樣:

var messageBox = new Mock<IMessageSvc>(); 
messageBox.Setup(x => x.Show(It.Is<string>(y => y == "Do you want to save changes?"), 
    It.Is<string>(y => y == "Save Changes"), 
    It.Is<MessageBoxButton>(y => y == MessageBoxButton.YesNoCancel), 
    It.Is<MessageBoxIcon>(y => y == MessageBoxIcon.Question), 
    It.Is<MessageBoxResult>(y => y == MessageBoxResult.Yes))) 
    .Returns(MessageBoxResult.Yes); 

mainViewModel.CloseCommand.Execute(new object()); 

messageBox.Verify(x => x.Show(It.Is<string>(y => y == "Do you want to save changes?"), 
    It.Is<string>(y => y == "Save Changes"), 
    It.Is<MessageBoxButton>(y => y == MessageBoxButton.YesNoCancel), 
    It.Is<MessageBoxIcon>(y => y == MessageBoxIcon.Question), 
    It.Is<MessageBoxResult>(y => y == MessageBoxResult.Yes))); 
+0

我以前試過這個,在這種情況下返回的錯誤是'期望調用模擬一次,但是用'messageBox.Verify(x => x.Show(0)> 0次' y ==「您想保存更改嗎?」), It.Is (y => y == ==「Save Changes」), It.Is (y => y == MessageBoxButton.YesNoCancel) , It.Is (y => y == MessageBoxIcon.Question), It.Is (y => y == MessageBoxResult.Yes)),Times.Once);' –

+0

我有我的IMessageService注入ViewModel並在Unit Test類中初始化,所以當我運行_messageSvc.Verify(x => x.Show(It.Is (y => y ==「你想保存更改嗎? ) It.Is (y => y == == Save Changes), It.Is (y => y == MessageBoxButton.YesNoCancel), It.Is (y => y = = MessageBoxIcon.Question), It.Is (y => y == MessageBoxResult.Yes)),Times.Once);'它工作,但我需要設置消息框以獲取返回值 –