2013-01-10 66 views
8

我正在使用Moq來驗證一個方法是否在我的單元測試中被調用。在這個特定情況下,我想測試被測方法是否通過log4net記錄錯誤。問題是,這可以通過調用log.Errorlog.ErrorFormat來完成。兩者都很好。如何驗證兩種方法之一是否已被調用?

我該如何驗證?我只知道如何確認他們都被叫了。

var logMock = new Mock<ILog>(); 

var myClass = new MyClass(logMock.Object); 

myClass.MyMethod(); 

logMock.Verify(log => log.Error(It.IsAny<object>())); 
logMock.Verify(log => log.ErrorFormat(It.IsAny<string>(), It.IsAny<object>())); 

現在我想起來了,他們都有一堆重載的,我不介意任何重載的被稱爲是(我開始懷疑這是一個很好的測試)。

在此先感謝。

編輯:我只是想的東西討厭:

try 
{ 
    logMock.Verify(log => log.Error(It.IsAny<object>())); 
} 
catch (Moq.MockException ex) 
{ 
    logMock.Verify(log => log.ErrorFormat(It.IsAny<string>(), It.IsAny<object>())); 
} 

也許我可以在某種擴展方法的包裝這個...例如VerifyAny

回答

9

你可以爲設置一個標誌,每個有效的錯誤方法註冊一個回調:

// Arrange 
bool errorFlag = false; 
logMock 
    .Setup(l => l.Error(It.IsAny<object>())) 
    .Callback((object o) => errorFlag = true); 

/* repeat setup for each logMock method */ 

// Act 
myClass.MyMethod(); 

// Assert 
Assert.IsTrue(errorFlag); 

當然,這仍然會是乏味的,如果你有很多的重載覆蓋。

編輯:爲了好玩,這裏是爲Mock<T>.VerifyAny擴展方法:

public static class MockExtensions 
{ 
    public static void VerifyAny<T>(this Mock<T> mock, params Expression<Action<T>>[] expressions) 
     where T: class 
    { 
     List<MockException> exceptions = new List<MockException>(); 
     bool success = false; 
     foreach (var expression in expressions) 
     { 
      try 
      { 
       mock.Verify(expression); 
       success = true; 
       break; 
      } 
      catch (MockException ex) 
      { 
       exceptions.Add(ex); 
      } 
     } 

     if (!success) 
     { 
      throw new AggregateException("None of the specified methods were invoked.", exceptions); 
     } 
    } 
} 

用法:

[TestMethod] 
public void FooTest() 
{ 
    Mock<IFoo> fooMock = new Mock<IFoo>(); 
    fooMock.Object.Bar1(); 

    fooMock.VerifyAny(
     f => f.Bar1(), 
     f => f.Bar2()); 
} 
+0

我VerifyAny的版本是關於那個以外,我沒有不一樣考慮類型約束並收集例外。這個用法實際上比CallBack方法更簡潔。或者是捕捉那樣的例外是一個壞主意?嗯...... –

+0

@MatthijsWessels捕捉像這樣的預期異常感覺有點骯髒,但對於單元測試項目,我不會擔心性能太多。也許最好有一個'Mock .SetupAny'方法來代替注入回調並返回一個布爾值。 –

1

,如果你是專門測試中記錄的一個特定的錯誤,爲什麼不能有2測試,其中一個確保log.Error被調用,另一個確保調用log.ErrorFormat,我假設您可以根據輸入控制調用哪一個。

,如果你還是想驗證一個或另一個,你可以使用這種方法,它正是你需要的:

Verify that either one method or the other was invoked in a unit test

+1

對「MyClass」的要求是它記錄錯誤級別日誌消息。錯誤,ErrorFormat及其重載都是這樣做的。對我來說,使用哪一個並不重要。您所鏈接的答案中指定的CallBack方法看起來像可以做我想做的事。儘管現在我懷疑Scott Wegner的VerifyAll或CallBacks。 –

相關問題