If an alternative instance is set with properties or methods, a non-null value is automatically returned. For example, if any property or method returns an interface, delegate, or pure virtual class *, it will automatically return an alternative to the instance itself. This is usually called recursive simulation technology and is very practical. For example, it can avoid explicitly setting each alternative instance, which means a smaller numberCode. For types such as string and array, null instead of null is returned by default.
* Note: A pure virtual class refers to a class. All its public methods and attributes are defined as virtual or abstract, in addition, it has a default public or protected field no-argument constructor.
Recursive Simulation
For example, we have the following types of definitions:
1 Public Interface Inumberparser 2 { 3 Int [] Parse ( String Expression ); 4 } 5 Public Interface Inumberparserfactory 6 { 7 Inumberparser create ( Char Delimiter ); 8 }
We want to configure inumberparserfactory to create a parser that returns a certain number of int type values for an expression. We can manually create each alternative instance:
1 [Testmethod] 2 Public Void Test_autorecursivemocks_manuallycreatesubstitutes () 3 { 4 VaR Factory = substitute. For <inumberparserfactory> (); 5 VaR Parser = substitute. For <inumberparser> (); 6 Factory. Create (' , ' ). Returns (parser ); 7 Parser. parse ( " An expression " ). Returns ( New Int [] { 1 , 2 , 3 }); 8 9 VaR Actual = factory. Create ( ' , ' ). Parse ( " An expression " ); 10 Collectionassert. areequal ( New Int [] { 1 , 2 , 3 }, Actual ); 11 }
Alternatively, the recursive simulation function can be applied. inumberparserfactory. Create () will automatically return an inumberparser type alternative instance.
1 [Testmethod] 2 Public Void Test_autorecursivemocks_automaticallycreatesubstitutes () 3 { 4 VaR Factory = substitute. For <inumberparserfactory> (); 5 Factory. Create ( ' , ' ). Parse ( " An expression " ). Returns ( New Int [] { 1 , 2 , 3 }); 6 7 VaR Actual = factory. Create (' , ' ). Parse ( " An expression " ); 8 Collectionassert. areequal ( New Int [] { 1 , 2 , 3 }, Actual ); 9 }
The same alternative instance is returned each time a simulated attribute or method is called with the same parameters. If different parameters are used, a new alternative instance is returned.
1 [Testmethod] 2 Public Void Test_autorecursivemocks_callrecursivelysubbed () 3 { 4 VaR Factory = substitute. For <inumberparserfactory> (); 5 Factory. Create ( ' , ' ). Parse ( " An expression " ). Returns ( New Int [] { 1 , 2 , 3 }); 6 7 VaR Firstcall = factory. Create ( ' , ' ); 8 VaR Secondcall = factory. Create ( ' , ' ); 9 VaR Thirdcallwithdiffarg = factory. Create ( ' X ' ); 10 11 Assert. aresame (firstcall, secondcall ); 12 Assert. arenotsame (firstcall, thirdcallwithdiffarg ); 13 }
Note: Do not create recursive substitution for ClassesInstanceBecause creating and using classes may have potential or unnecessary side effects. Therefore, it is necessary to explicitly create and replace the return classInstance.
Substitution chain
When needed, we can use recursive simulation to easily set the substitution chain, but this is not an ideal practice. For example:
1 Public Interface Icontext 2 { 3 Irequest currentrequest { Get ;} 4 } 5 Public Interface Irequest 6 { 7 Iidentity identity { Get ;} 8 Iidentity newidentity ( String Name ); 9 } 10 Public Interface Iidentity 11 { 12 String Name { Get ;} 13 String [] Roles (); 14 }
If you want to obtain the identity in currentrequest and return a name, you can manually create alternatives for icontext, irequest, and iidentity, and then use returns () to link these alternative instances together. Alternatively, we can use an alternative instance that is automatically created for attributes and methods.
1 [Testmethod] 2 Public Void Test_autorecursivemocks_substitutechains () 3 { 4 VaR Context = substitute. For <icontext>(); 5 Context. currentrequest. Identity. Name. Returns ( " My pet fish Eric " ); 6 Assert. areequal ( 7 " My pet fish Eric " , 8 Context. currentrequest. Identity. Name ); 9 }
Here, currentreques t automatically returns an irequest replacement instance. The irequest replacement instance automatically returns an iidentity replacement instance.
Note: This Long replacement instance chain is generally considered code Odor: we break the law of Demeter principle, and objects should only deal with adjacent objects directly related to them, instead of dealing with near objects. If recursive simulation is not used in the test case you write, the setting process may be significantly complicated. Therefore, if you want to use recursive mode, pay special attention to similar type coupling.
Automatic Value
When a value of the string or array type is returned for an attribute or method, null or non-null values are returned by default. For example, if you only need to return an object reference but do not care about its specific attributes, this function can help you avoid null reference exceptions.
1 [Testmethod]2Public VoidTest_autorecursivemocks_autovalues ()3 {4VaRIdentity = substitute. For <iidentity>();5Assert. areequal (String. Empty, identity. Name );6Assert. areequal (0, Identity. roles (). Length );7}