Static Mocking
Static mocking is one of the advanced features supported inTelerik® JustMock. It allows you to fake static constructors, methods and properties calls, set expectations and verify results using theAAAprinciple.
We can divide static mocking into the following major parts:
- Static constructor mocking
- Static method mocking
- Extension methods mocking
This is an Elevated Feature. Refer tothistopic to learn more about the differences between both the commercial and free versions of Telerik JustMock.
Further in this topic we will use the following sample code to illustrate how to mock static constructors, methods and properties.
public class Foo { static Foo() { throw new NotImplementedException(); } public static void Submit() { } public static int Execute(int arg) { throw new NotImplementedException(); } public static int FooProp { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } } internal class FooInternal { internal static void DoIt() { throw new NotImplementedException(); } } public static class FooStatic { public static void Do() { throw new NotImplementedException(); } }
Public Class Foo Shared Sub New() Throw New NotImplementedException() End Sub Public Shared Sub Submit() Throw New NotImplementedException() End Sub Public Shared Function Execute(arg As Integer) As Integer Throw New NotImplementedException() End Function Public Shared Property FooProp As Integer Get Throw New NotImplementedException() End Get Set(value As Integer) Throw New NotImplementedException() End Set End Property End Class Friend Class FooInternal Friend Shared Sub DoIt() Throw New NotImplementedException() End Sub End Class Public NotInheritable Class FooStatic Private Sub New() End Sub Public Shared SubDoThrow New NotImplementedException() End Sub End Class
Important
To use static mocking you first need to go to elevated mode by enabling JustMock from the menu.How to Enable/Disable
Static Constructor Mocking
In the following example you will see how you can specify the behavior of the static constructor when the target type is mocked. The first thing you need to do is to set up the target type for mocking all static calls. You do this using one of the following calls to theMock.SetupStatic
method.
void Mock.SetupStatic( Type staticType ); void Mock.SetupStatic( Type targetType, Behavior behavior ); void Mock.SetupStatic( Type staticType, StaticConstructor staticConstructor ); void Mock.SetupStatic( Type targetType, Behavior behavior, StaticConstructor staticConstructor );
As you can see you have a number of choices. You always have to provide the type of the target class you want to set up for mocking. You can also specify the behavior of the mock. The default behavior isBehavior.Loose.
TheStaticConstructor
parameter defines the default behavior of the static constructor. You can choose from the following values:
- NonMocked
- Mocked
The default value for this property isNonMocked
.
Let's see a complete example using the classFoo
from the sample code in the beginning.
[TestMethod] public void ShouldArrangeStaticFunction() { // Arrange Mock.SetupStatic(typeof(Foo), StaticConstructor.Mocked); int expected = 0; Mock.Arrange(() => Foo.FooProp).Returns(0); // Assert Assert.AreEqual(expected, Foo.FooProp); }
Public Sub ShouldArrangeStaticFunction() ' Arrange Mock.SetupStatic(GetType(Foo), StaticConstructor.Mocked) Dim expected As Integer = 0 Mock.Arrange(Function() Foo.FooProp).Returns(0) ' Assert Assert.AreEqual(expected, Foo.FooProp) End Sub
Here we have set up the static constructor mock of the target typeFoo
. Using theStaticConstructor
parameter in the call toSetupStatic
我们有指定的that we want to mock the call to the static constructor and therefore the call to theFoo.FooProp
will not throw aNotImplementedException
.
General Static Method Mocking
Let's start with the simplest example, namely how to mock the staticSubmit
method. First, we need to call the following:
Mock.SetupStatic(typeof(Foo), StaticConstructor.Mocked);
Mock.SetupStatic(GetType(Foo), StaticConstructor.Mocked)
This call setups theFoo
type for static mocking and prepares all the static methods as mockable.
This is actually the only difference between static and instance mocking. From now on you continue as if you are mocking instance methods.
Foo.Submit ();
Foo.Submit()
In theSubmit
method implementation we throw an exception, but as we mocked theFoo
class that exception should not be thrown. Finally, we can assert that the method was actually called.
Mock.Assert(() => Foo.Submit());
Foo.Submit Mock.Assert(子()())
WithMock.SetupStatic(typeof(Foo), StaticConstructor.Mocked);
we setup thatallstatic methods from this class will me mocked. In certain cases you'd need to mock only methods that are setup withMock.Arrange
. To achieve this you need to set the M:Telerik.JustMock.Behavior toStrict
in theMock.SetupStatic
call.
[TestMethod] [ExpectedException(typeof(StrictMockException))] public void ShouldThrowWhenNotArranged() { //Arrange Mock.SetupStatic(typeof(Foo), Behavior.Strict, StaticConstructor.Mocked); Mock.Arrange(() => Foo.Execute(10)).Returns(10); //Assert Assert.AreEqual(10, Foo.Execute(10)); // Act // throws MockException as there is no arrange associated with the Submit method Foo.Submit(); }
Public Sub ShouldThrowWhenNotArranged() ' Arrange Mock.SetupStatic(GetType(Foo), Behavior.Strict, StaticConstructor.Mocked) Mock.Arrange(Function() Foo.Execute(10)).Returns(10) ' Assert Assert.AreEqual(10, Foo.Execute(10)) ' Act ' Throws MockException as there is no arrange associated with the Submit method. Foo.Submit() End Sub
Once we set the M:Telerik.JustMock.Behavior toStrict
, only calls setup through arrange are mocked. Other calls will throw aMockException
.
Mocking Static Property Get
You can also set up a static property get:
[TestMethod] public void ShouldFakeStaticPropertyGet() { // Arrange Mock.SetupStatic(typeof(Foo), Behavior.Strict, StaticConstructor.Mocked); bool called = false; Mock.Arrange(() => Foo.FooProp).DoInstead(() => { called = true; }).Returns(1); // Assert Assert.AreEqual(Foo.FooProp, 1); Assert.IsTrue(called); }
Public Sub ShouldFakeStaticPropertyGet() ' Arrange Mock.SetupStatic(GetType(Foo), Behavior.Strict, StaticConstructor.Mocked) Dim called As Boolean = False Mock.Arrange(Function() Foo.FooProp).DoInstead(Sub() called = True).Returns(1) ' Act Assert.AreEqual(Foo.FooProp, 1) Assert.IsTrue(called) End Sub
We replace the actual implementation ofFoo.FooProp
withcalled = true;
and return1
. After acting we verify that the method was actually called with return value1
.
Mocking Static Property Set
Now, let's mock a static property set. In the example below, we arrange theFoo.FooProp
property. We useDoInstead
to set a local boolean variable totrue
once it is assigned10
. After that, we verify that what we have expected actually happened in our test.
[TestMethod] public void ShouldFakeStaticPropertySet() { // Arrange Mock.SetupStatic(typeof(Foo), Behavior.Strict, StaticConstructor.Mocked); bool called = false; Mock.ArrangeSet(() => { Foo.FooProp = 10; }).DoInstead(() => { called = true; }); // Act - this line should not throw any mockexception. Foo.FooProp = 10; // Assert Assert.IsTrue(called); }
Public Sub ShouldFakeStaticPropertySet() ' Arrange Mock.SetupStatic(GetType(Foo), Behavior.Strict, StaticConstructor.Mocked) Dim called As Boolean = False Mock.ArrangeSet(Sub() Foo.FooProp = 10).DoInstead(Sub() called = True) ' Act - this line should not throw any mockexception. Foo.FooProp = 10 ' Assert Assert.IsTrue(called) End Sub
Go toMock Propertiestopic to learn more about mocking properties.
Mocking Internal Static Call
Going further, you can mock internal methods like in the following example.
[TestMethod] public void ShouldFakeInternalStaticCall() { // Arrange Mock.SetupStatic(); // Act FooInternal.DoIt(); }
Public Sub ShouldFakeInternalStaticCall() ' Arrange Mock.SetupStatic(Of FooInternal)() ' Act FooInternal.DoIt() End Sub
Here, callingFooInternal.DoIt
should not throw an exception as you are allowed to setup static internal methods.
Mocking Static Class
In the demonstrated examples, the class itself that we mock is anon staticclass - only the methods are static. To mock a static class you need to use the non generic version of theMock.SetupStatic
method, i.e.
[TestMethod] public void ShouldMockStaticClass() { // Arrange Mock.SetupStatic(typeof(FooStatic)); // Act - doesn't throw MockException FooStatic.Do(); }
Public Sub ShouldMockStaticClass() ' Arrange Mock.SetupStatic(GetType(FooStatic)) ' Act - doesn't throw MockException FooStatic.DoEnd Sub
Mocking Static Members Across Threads
Mocking static members across all threads is an unsafe operation that may compromise the stability of the testing framework. Arrangements on static members are valid only for the current thread by default. To make an arrangement on a static member valid on all threads, add the .OnAllThreads() clause to the arrangement:
Mock.Arrange(() => DateTime.Now).Returns(new DateTime()).OnAllThreads();
Mocking Current HttpContext
Here is an example how to mock thecurrent HTTP context.
We arrange a call toHttpContext.Current
to set a local variable totrue
. Note that the original implementation ofHttpContext.Current
won`t be executed.
[TestMethod] public void ShouldAssertMockingHttpContext() { // Arrange bool called = false; Mock.Arrange(() => HttpContext.Current).DoInstead(() => called = true); // Act var ret = HttpContext.Current; // Assert Assert.IsTrue(called); }
_ Public Sub ShouldAssertMockingHttpContext() ' Arrange Dim called As Boolean = False Mock.Arrange(Function() HttpContext.Current).DoInstead(Sub() called = True) ' Act Dim ret = HttpContext.Current ' Assert Assert.IsTrue(called) End Sub
After acting we verify against our expectations.
Mocking Extension Methods
扩展方法使您能够“添加”方法existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static methods, but they are called as if they were instance methods on the extended type.
Mocking extension method is similar to mocking any instance methods. The only difference is that we don’t needMock.Create
call to initialize the class for mocking as extension mocking is by default partial.
Let's see an example of how to mock extension methods. Consider the following class:
public class Bar { public void Execute() { throw new NotImplementedException(); } }
Public Class Bar Public Sub Execute() Throw New NotImplementedException() End Sub End Class
And a class that contains extension methods for theFoo
class:
public static class BarExtensions { public static int Echo(this Bar foo, int arg) { return default(int); } }
Public Module BarExtensions Public Function Echo(foo As Bar, arg As Integer) As Integer Return 0 End Function End Module
Let's mock theEcho
extension method.
[TestMethod] public void ShouldFakeExtensionMethod() { // Arrange var foo = new Bar(); Mock.Arrange(() => foo.Echo(10)).Returns(11); // Act var actual = foo.Echo(10); // Assert Assert.AreEqual(11, actual); }
Public Sub ShouldFakeExtensionMethod() ' Arrange Dim foo = New Bar() Mock.Arrange(Function() foo.Echo(10)).Returns(11) ' Act Dim actual = foo.Echo(10) ' Assert Assert.AreEqual(11, actual) End Sub
First we create an instance of theFoo
class. Notice that we create a standard instance of the class, not a mock instance. Then we setup the call toEcho
throughArrange
in the same way we do it for non static methods. Finally, we assert the return value as usual.