創建一個替代實例的基本語法:
var substitute = Substitute.For<ISomeInterface>();
這就是通常情況下你創建一個類型的替代實例的方法。一般來說,這個類型是一個接口,但是在一些特殊情況下,也可以對類進行替代。
警告:類的替代可能會有一些不太好的副作用。NSubstitute 只能作用於類中的虛擬成員,所以類中的任何非虛成員代碼將都會被真實的執行。如果你嘗試替代一個類,而該類會在其構造函數或某個非虛屬性中格式化硬盤,那么你就是自討苦吃了。如果可能的話,請堅持只替代接口類型。
在知道了我們不會替代類類型之后,此處描述如何為一個具有含參構造函數的類創建替代實例:
var someClass = Substitute.For<SomeClassWithCtorArgs>(5, "hello world");
對於具有默認構造函數的類,創建其替代實例的語法與替代接口一樣。
替代多個接口
有些時候,你可能需要為多個類型創建替代實例。一個最好的例子就是,當你有代碼使用了某類型后,需要檢查是否其實現了 IDisposable 接口,並且確認是否調用了 Dispose 進行類型銷毀。
1 public interface ICommand : IDisposable 2 { 3 void Execute(); 4 } 5 6 public class CommandRunner 7 { 8 private ICommand _command; 9 10 public CommandRunner(ICommand command) 11 { 12 _command = command; 13 } 14 15 public void RunCommand() 16 { 17 _command.Execute(); 18 _command.Dispose(); 19 } 20 } 21 22 [TestMethod] 23 public void Test_CreatingSubstitute_MultipleInterfaces() 24 { 25 var command = Substitute.For<ICommand, IDisposable>(); 26 27 var runner = new CommandRunner(command); 28 runner.RunCommand(); 29 30 command.Received().Execute(); 31 ((IDisposable)command).Received().Dispose(); 32 }
通過這種方法,替代實例可以實現多個類型。但請記住,一個類最多只能實現一個類。如果你願意的話,你可以指定多個接口,但是其中只能有一個是類類型。為多個類型創建替代實例的最靈活的方式是使用重載。
1 public class SomeClassWithCtorArgs : IDisposable 2 { 3 public SomeClassWithCtorArgs(int arg1, string arg2) 4 { 5 } 6 7 public void Dispose() { } 8 } 9 10 [TestMethod] 11 public void Test_CreatingSubstitute_SpecifiedOneClassType() 12 { 13 var substitute = Substitute.For( 14 new[] { typeof(ICommand), typeof(IDisposable), typeof(SomeClassWithCtorArgs) }, 15 new object[] { 5, "hello world" } 16 ); 17 Assert.IsInstanceOfType(substitute, typeof(ICommand)); 18 Assert.IsInstanceOfType(substitute, typeof(IDisposable)); 19 Assert.IsInstanceOfType(substitute, typeof(SomeClassWithCtorArgs)); 20 }
替代委托
通過使用 Substiute.For<T>() 語法,NSubstitute 可以為委托類型創建替代。當為委托類型創建替代時,將無法使該替代實例實現額外的接口或類。
1 [TestMethod] 2 public void Test_CreatingSubstitute_ForDelegate() 3 { 4 var func = Substitute.For<Func<string>>(); 5 func().Returns("hello"); 6 Assert.AreEqual<string>("hello", func()); 7 }