-
Notifications
You must be signed in to change notification settings - Fork 21
Final Mocking by Telerik JustMock
This is one of the series that implements the samples that are in the official documents of JustMock. Let's migrate Final Mocking samples to Prig.
In this sample, I employ the configuration that is added multiple projects to one solution because these are series(see also Sealed Mocking, Static Mocking):
Now, I notice that this sample is different from previous samples(Moles, Fakes), because the targets which are called indirectly are contained in the assembly which doesn't belong to GAC. Until now, it was no problem to perform the steps that make indirection stubs in the Package Manager Console. But now, I recommend that you also become to be able to use PowerShell. The Package Manager Console doesn't support nested prompt by its design. Therefore, there is the problem that it can never release the assemblies if it loaded the assemblies to analyze indirection targets once. In the first place, the features that are used mundanely - such as autocompletion, commands history and so on - are less functionality than PowerShell's. I think it is efficient that you had better use the Package Manager Console when adding Stub Settings File or run tests, and you had better use PowerShell when analyzing a assembly.
NOTE: In the following explanation, note that the commands that start with PM>
are run in the Package Manager Console, but the commands that start with PS>
are run in the PowerShell.
After building FinalMockingMigration
, select the context menu Add Prig Assembly
to add the indirection setting:
Then, right click FinalMockingMigration.v4.0.30319.v1.0.0.0.prig
and select the context menu Edit Prig Indirection Settings
:
If the operation is succeeded, the following window will be shown:
Welcome to Prig Setup Session!!
You can add the indirection settings from here. In this session, you can use `$ReferencedAssemblies` that contains all
referenced assemblies information of current project. For example, if you want to get the indirection settings for all
members of the type `Foo` that belongs to the referenced assembly `UntestableLibrary`, the following commands will achi
eve it:
PS> $ReferencedAssemblies
FullName
--------
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
UntestableLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
PS> padd -ra $ReferencedAssemblies[-1]
PS> $ReferencedAssemblies[-1].GetTypes() | ? { $_.Name -eq 'Foo' } | pfind | pget | clip
PS> exit # Then, paste the content on the clipboard to the Stub Settings File(e.g. `UntestableLibrary.v4.0.30319.v1.0.
0.0.prig`).
See also the command's help `padd`, `pfind` and `pget`.
Current Project: FinalMockingMigrationTest
WARNING: Change the Current Project from `Default Project: ` on the Package Manager Console if it isn't what you want.
-EditorialInclude parameter is specified. You can also use the global variable $TargetReferencedAssembly in addition to
$ReferencedAssemblies. Currently $TargetReferencedAssembly is:
FullName
--------
FinalMockingMigration, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
PS 10.JustMockMigration>
As shown by the introduction on the prompt, you can get the indirection setting and analyze target assembly more easily than the Package Manager Console.
OK, let's analyze the assembly immediately. When confirming $TargetReferencedAssembly
's types by GetTypes
, you can see that the top 3 are targets. So, apply the filter that is same as previous against them:
PS 10.JustMockMigration> $TargetReferencedAssembly.GetTypes()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False Foo System.Object
False True EchoEventHandler System.MulticastDelegate
True False FooGeneric System.Object
False False Program System.Object
PS 10.JustMockMigration> $TargetReferencedAssembly.GetTypes()[0..2] | % { $_.GetMembers() } | ? { $_ -is [System.Reflection.MethodBase] } | ? { !$_.IsAbstract } | ? { $_.DeclaringType -eq $_.ReflectedType }
Method
------
Int32 Execute(Int32, Int32)
Int32 Execute(Int32)
Int32 Echo(Int32)
System.String get_FooProp()
Void set_FooProp(System.String)
Void add_OnEchoCallback(EchoEventHandler)
Void remove_OnEchoCallback(EchoEventHandler)
Void .ctor()
Void Invoke(Boolean)
System.IAsyncResult BeginInvoke(Boolean, System.AsyncCallback, System.Object)
Void EndInvoke(System.IAsyncResult)
Void .ctor(System.Object, IntPtr)
TRet Echo[T,TRet](T)
Void .ctor()
PS 10.JustMockMigration>
If you feel good about the filtered results, convert to the Indirection Stub Setting, then copy to clipboard. Also, if you want to release the assembly that are finished analysis, you can do it by exiting the nested prompt:
PS 10.JustMockMigration> $TargetReferencedAssembly.GetTypes()[0..2] | % { $_.GetMembers() } | ? { $_ -is [System.Reflection.MethodBase] } | ? { !$_.IsAbstract } | ? { $_.DeclaringType -eq $_.ReflectedType } | pget | clip
PS 10.JustMockMigration> exit
Go back to Visual Studio, and paste the Indirection Stub Setting to FinalMockingMigration.v4.0.30319.v1.0.0.0.prig
. Did it build successfully? OK, this introduction has become quite long, but let's migrate actually!
###Assert Final Method Setup As described in the sample for Fakes, I recommend that you use Prig together with another mocking framework like Moq, because Prig has no feature as a Mock Object. However, almost JustMock's samples are just introduced the behavior as a Test Stub, so I also make Prig's samples consistent with it.
At first, let's replace the return value of a final method:
[Test]
public void Prig_should_setup_a_call_to_a_final_method()
{
using (new IndirectionsContext())
{
// Arrange
var fooProxy = new PProxyFoo();
fooProxy.EchoInt32().Body = (@this, arg1) => 10;
var foo = (Foo)fooProxy;
// Act
var actual = foo.Echo(1);
// Assert
Assert.AreEqual(10, actual);
}
}
At the statement fooProxy.EchoInt32().Body = (@this, arg1) => 10;
, Prig replaces the final method to the procedure that returns the constant value 10. I'm sure you are all right. Let's go next!
###Assert Property Get This is the example that replaces a final property:
[Test]
public void Prig_should_setup_a_call_to_a_final_property()
{
using (new IndirectionsContext())
{
// Arrange
var fooProxy = new PProxyFoo();
fooProxy.FooPropGet().Body = @this => "bar";
var foo = (Foo)fooProxy;
// Act
var actual = foo.FooProp;
// Assert
Assert.AreEqual("bar", actual);
}
}
At the statement fooProxy.FooPropGet().Body = @this => "bar";
, Prig replaces the final property to the procedure that returns the constant value "bar". Let's keep on going :D
###Assert Property Set This example is verifying the setter of a final property. In this example, I think that it is easier to use Moq:
[Test]
[ExpectedException(typeof(MockException))]
public void Prig_should_assert_property_set()
{
using (new IndirectionsContext())
{
// Arrange
var fooProxy = new PProxyFoo();
var fooPropSetMock = new Mock<IndirectionAction<Foo, string>>(MockBehavior.Strict);
fooPropSetMock.Setup(_ => _(fooProxy, "ping"));
fooProxy.FooPropSetString().Body = fooPropSetMock.Object;
var foo = (Foo)fooProxy;
// Act, Assert
foo.FooProp = "foo";
}
}
Telerik.JustMock.Behavior.Strict
falls into Moq.MockBehavior.Strict
. Therefore, if you call the target member with any arguments that aren't satisfied the specified condition at Setup
, it will become to throw MockException
.
###Assert Method Overloads Let's replace each final method overloads. I believe that you will not hesitate at all if you added the Indirection Stub Setting correctly.
[Test]
public void Prig_should_assert_on_method_overload()
{
using (new IndirectionsContext())
{
// Arrange
var fooProxy = new PProxyFoo();
fooProxy.ExecuteInt32().Body = (@this, arg1) => arg1;
fooProxy.ExecuteInt32Int32().Body = (@this, arg1, arg2) => arg1 + arg2;
var foo = (Foo)fooProxy;
// Act, Assert
Assert.AreEqual(1, foo.Execute(1));
Assert.AreEqual(2, foo.Execute(1, 1));
}
}
There is no significant problem? Let's go next.
###Assert Method Callbacks This example explains replacing such callback as an event. Although I introduced in the example for Moles, it requests a little technique to implement.
[Test]
public void Prig_should_assert_on_method_callbacks()
{
using (new IndirectionsContext())
{
// Arrange
var handler = default(Foo.EchoEventHandler);
var fooProxy = new PProxyFoo();
fooProxy.AddOnEchoCallbackFooEchoEventHandler().Body = (@this, value) => handler += value;
fooProxy.EchoInt32().Body = (@this, arg1) => { handler(true); return arg1; };
var foo = (Foo)fooProxy;
var called = false;
foo.OnEchoCallback += echoed => called = echoed;
// Act
foo.Echo(10);
// Assert
Assert.IsTrue(called);
}
}
The implementation flow is as the followings:
- Like the statement
fooProxy.AddOnEchoCallbackFooEchoEventHandler().Body = (@this, value) => handler += value;
, hijack the subscript operator(+=
) of the event you want to replace, and bind the passed handler(value
) to the delegate for testing(handler
). - At the timing that you want to raise the original event, invoke the delegate that is bound at step 1(
handler
) instead of it.
This will enable that you get the effect that is same as to fire the original event.
###Assert Generic Types and Methods This is the example that replaces generic types and methods:
[Test]
public void Prig_should_assert_on_generic_types_and_method()
{
using (new IndirectionsContext())
{
// Arrange
var expected = "ping";
var fooGenericProxy = new PProxyFooGeneric();
fooGenericProxy.EchoOfTOfTRetT<string, string>().Body = (@this, s) => s;
var fooGeneric = (FooGeneric)fooGenericProxy;
// Act
var actual = fooGeneric.Echo<string, string>(expected);
// Assert
Assert.AreEqual(expected, actual);
}
}
You know, very easy! See also the main feature's explanation.
Complete source code is here.
-
Home
- QUICK TOUR [SRC]
- FEATURES
- CHEAT SHEET
- PACKAGE MANAGER CONSOLE POWERSHELL REFERENCE
- COMMAND LINE REFERENCE
- APPVEYOR SUPPORT
- MIGRATION
- From Microsoft Research Moles [SRC]
- From Microsoft Fakes [SRC]
- From Telerik JustMock [SRC]
- From Typemock Isolator [SRC]