静态模拟
中支持的高级特性之一是静态模拟Telerik®JustMock.它允许你伪造静态构造函数,方法和属性调用,设置期望和验证结果使用AAA原则。
我们可以将静态模拟分为以下几个主要部分:
- 静态构造函数模拟
- 静态方法模拟
- 扩展方法模拟
这是一个高架特征。指这主题,以了解更多关于Telerik JustMock的商业版本和免费版本之间的差异。
在本主题中,我们将使用以下示例代码来演示如何模拟静态构造函数、方法和属性。
公共类Foo{静态Foo(){抛出新的NotImplementedException();} public static void Submit() {} public static int Execute(int arg) {throw new NotImplementedException();} public static int FooProp {get{抛出新的NotImplementedException();} set{抛出新的NotImplementedException();}}}内部类FooInternal{内部静态void DoIt(){抛出新的NotImplementedException();}}公共静态类FooStatic{公共静态void Do(){抛出新的NotImplementedException();}}
公共类Foo共享子新()抛出新NotImplementedException()结束子公共共享子提交()抛出新的NotImplementedException()子公共共享函数执行结束(arg整数)整数把新NotImplementedException()结束函数公共共享属性为必选的整数买把新NotImplementedException()结束获得组(值为整数)把新NotImplementedException()端设置结束属性端类朋友类FooInternal朋友共享子DoIt()抛出新的NotImplementedException()结束子结束类Public非继承类FooStatic Private Sub New()结束子Public共享子做抛出新的NotImplementedException()结束子结束类
重要的
要使用静态模拟,首先需要从菜单中启用JustMock,从而进入提升模式。如何启用/禁用
静态构造函数模拟
在下面的示例中,您将看到如何在模拟目标类型时指定静态构造函数的行为。您需要做的第一件事是为模拟所有静态调用设置目标类型。对象的下列调用之一可以完成此操作模拟。SetupStatic
方法。
无效的模拟。SetupStatic(类型staticType);无效的模拟。SetupStatic(类型targetType,行为行为);无效的模拟。SetupStatic(类型staticType, StaticConstructor);无效的模拟。SetupStatic(类型targetType,行为行为,静态构造函数);
正如你所看到的,你有很多选择。您总是必须提供您想要为模拟设置的目标类的类型。您还可以指定模拟的行为。默认行为为的行为。宽松的.
的StaticConstructor
参数定义静态构造函数的默认行为。可以从以下值中选择:
- NonMocked
- 嘲笑
此属性的默认值为NonMocked
.
让我们来看一个使用该类的完整示例喷火
从示例代码开始。
[TestMethod] public void ShouldArrangeStaticFunction(){//安排Mock.SetupStatic(typeof(Foo), staticconstructor . mock);Int期望= 0;Mock.Arrange(() => Foo.FooProp).Returns(0);// Assert。AreEqual(预期,Foo.FooProp);}
公共子ShouldArrangeStaticFunction() '排列Mock.SetupStatic(GetType(Foo), staticconstructor . mock) Dim expected As Integer = 0 Mock.Arrange(Function() Foo. fooprop).Returns(0) '维护维护。AreEqual(expected, Foo.FooProp)结束Sub
这里我们已经设置了目标类型的静态构造函数mock喷火
.使用StaticConstructor
的调用中的参数SetupStatic
方法的调用,因此要模拟对静态构造函数的调用Foo。喷火Prop
不会扔NotImplementedException
.
通用静态方法模拟
让我们从最简单的示例开始,即如何模拟静态提交
方法。首先,我们需要调用以下函数:
Mock.SetupStatic (typeof (Foo), StaticConstructor.Mocked);
Mock.SetupStatic(方法(Foo), StaticConstructor.Mocked)
这个调用设置喷火
类型为静态模拟,并将所有静态方法准备为可mock。
这实际上是静态模拟和实例模拟之间的唯一区别。从现在开始,您可以继续模拟实例方法。
Foo.Submit ();
Foo.Submit ()
在提交
方法实现时抛出异常,但由于我们模拟了喷火
不应抛出异常的类。最后,我们可以断言该方法实际上被调用了。
Mock.Assert(() => Foo.Submit());
Foo.Submit Mock.Assert(子()())
与Mock.SetupStatic (typeof (Foo), StaticConstructor.Mocked);
我们设置好了所有来自这个类的静态方法将被嘲笑。在某些情况下,您只需要模拟设置时使用的方法模拟。安排
.要实现这一点,您需要设置M:Telerik.JustMock。行为严格的
在模拟。SetupStatic
调用。
[TestMethod] [ExpectedException(typeof(StrictMockException))]公共无效shouldthrowwhen公证书(){//安排Mock.SetupStatic(typeof(Foo),行为。严格,StaticConstructor.Mocked);Mock.Arrange(() => Foo.Execute(10)).Returns(10);/ /维护维护。Foo.Execute AreEqual(10日(10));// Act //抛出MockException,因为没有与提交方法Foo.Submit()相关的安排;}
Public Sub shouldthrowwhen公证书()'排列Mock.SetupStatic(GetType(Foo),行为。严格的, 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
一旦我们设置M:Telerik.JustMock。行为严格的
,只有调用通过安排设置被模拟。其他调用将抛出MockException
.
下面是一个在f#中模拟静态方法的例子:
[] member this.ShouldMockStaticCall() = Mock. setupstatic () Mock。排列(fun ignore -> Foo.EchoStatic()).Returns(1);断言。AreEqual (Foo.EchoStatic ())
EchoStatic
方法设置为返回1
.模拟静态属性获取
你也可以设置一个静态属性get:
[TestMethod] public void ShouldFakeStaticPropertyGet(){//安排Mock.SetupStatic(typeof(Foo),行为。严格,StaticConstructor.Mocked);Bool called = false;Mock.Arrange(() => Foo.FooProp).DoInstead(() => {called = true;}) .Returns (1);// Assert. areequal必选1);Assert.IsTrue(称为);}
Public Sub ShouldFakeStaticPropertyGet() '排列Mock.SetupStatic(GetType(Foo),行为。严格的, 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
我们替换了的实际实现Foo。喷火Prop
与Called = true;
并返回1
.在执行操作之后,我们验证该方法是否实际被调用并返回值1
.
模拟静态属性集
现在,让我们模拟一个静态属性集。在下面的例子中,我们排列Foo。喷火Prop
财产。我们使用DoInstead
将局部布尔变量设置为真正的
一旦它被分配10
.在此之后,我们验证我们所期望的在我们的测试中确实发生了。
[TestMethod] public void ShouldFakeStaticPropertySet(){//安排Mock.SetupStatic(typeof(Foo),行为。严格,StaticConstructor.Mocked);Bool called = false;Mock.ArrangeSet(() => {Foo。FooProp = 10;}).DoInstead(() => {called = true;});// Act -这一行不应该抛出任何mockexception。Foo。喷火Prop = 10; // Assert Assert.IsTrue(called); }
Public Sub ShouldFakeStaticPropertySet() '排列Mock.SetupStatic(GetType(Foo),行为。严格的, 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
去模拟属性主题以了解有关模拟属性的更多信息。
模拟内部静态调用
更进一步,您可以模拟内部方法,如下面的示例所示。
[TestMethod] public void ShouldFakeInternalStaticCall() {// Arrange Mock.SetupStatic();// Act FooInternal.DoIt();}
公共子ShouldFakeInternalStaticCall() '安排模拟。SetupStatic(Of FooInternal)() ' Act FooInternal.DoIt() End Sub
在这里,叫FooInternal。DoIt
不应抛出异常,因为允许设置静态内部方法。
模拟静态类
在演示的示例中,我们模拟的类本身是非静态类——只有方法是静态的。类的非泛型版本来模拟静态类模拟。SetupStatic
方法,即。
[TestMethod] public void ShouldMockStaticClass() {// Arrange Mock.SetupStatic(typeof(FooStatic));//不抛出MockException FooStatic.Do();}
公共子ShouldMockStaticClass() '排列Mock.SetupStatic(GetType(FooStatic)) 'Act -不抛出MockException FooStatic。做终止子
跨线程模拟静态成员
跨所有线程模拟静态成员是一种不安全的操作,可能会损害测试框架的稳定性。默认情况下,静态成员上的排列仅对当前线程有效。要使一个静态成员的排列在所有线程上都有效,在该排列中添加.OnAllThreads()子句:
Mock.Arrange(() => DateTime.Now)。返回(新DateTime ()) .OnAllThreads ();
模拟当前HttpContext
下面是一个如何模拟的例子当前HTTP上下文.
我们安排了一个电话HttpContext。当前的
设置局部变量为真正的
.注意,原来的实现HttpContext。当前的
不会被执行。
[TestMethod] public void ShouldAssertMockingHttpContext(){//排列bool called = false;Mock.Arrange(() => HttpContext.Current).DoInstead(() => called = true);// Act var ret = HttpContext.Current;// Assert. istrue(被调用);}
_ Public Sub ShouldAssertMockingHttpContext() '将Dim调用为Boolean = False Mock.Arrange(Function() HttpContext.Current).DoInstead(Sub() called = True) 'Act Dim ret = HttpContext。当前的' Assert Assert.IsTrue(called) End Sub
行动之后,我们验证我们的期望。
模拟扩展方法
扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。扩展方法是一种特殊的静态方法,但是调用它们时就像调用扩展类型的实例方法一样。
模拟扩展方法类似于模拟任何实例方法。唯一的区别是我们不需要Mock.Create T < > ()
默认情况下,将类初始化为扩展模拟的调用是局部的。
让我们看一个如何模拟扩展方法的示例。考虑下面的类:
公共类Bar{公共无效Execute(){抛出新的NotImplementedException();}}
公共类Bar公共子Execute()抛出新的NotImplementedException()结束子结束类
类的扩展方法喷火
类:
public static class BarExtensions {public static int Echo(this Bar foo, int arg){返回默认值(int);}}
Public Module BarExtensions Public Function Echo(foo As Bar, arg As Integer) As Integer Return 0 End Function结束模块
让我们来模拟一下回声
扩展方法。
[TestMethod] public void ShouldFakeExtensionMethod(){//排列var foo = new Bar();Mock.Arrange(() => foo.Echo(10)).Returns(11);// Act var actual = foo.Echo(10);// Assert。实际AreEqual(11日);}
公共子ShouldFakeExtensionMethod() '排列Dim foo = New Bar() Mock.Arrange(Function() foo. echo (10)).Returns(11) 'Act Dim实际= foo.Echo(10) '维护维护。AreEqual(11, actual)结束
类的实例喷火
类。注意,我们创建的是类的标准实例,而不是模拟实例。然后设置对的调用回声
通过安排
对于非静态方法,我们也是这样做的。最后,我们像往常一样断言返回值。