I was wondering if JusyMock could easily "intercept" object creation and replace them with fakes created on the fly?
I'm trying to unit test a method that, amongs other things, creates an instance of an object of a certain type and then uses it. The instance is NOT injected into the method and so I cannot control what instance is used inside the method...
I know that some other mocking framework do support Future Objects mocking. Is it the case with JustMock ?
Thanks for your time,
Vincent Grondin
EDIT: I think I need the "Weaver" library to accomplish this, can someone from telerik tell me if this library is included in the FREE version of JustMock?
15 Answers, 1 is accepted
Thank you for raising the question. Good news is that it is possible to mock future objects using the current build of JustMock (commercial / full). To best simulate the scenario, let's consider a method that internally creates the instance of login service to validate a particular user:
public
class
LegacyCode
{
public
int
CheckUser(
string
userName,
string
password)
{
var _service =
new
LoginService();
return
_service.ValidateUser(userName, password);
}
}
Note that the instance is created on the fly and the target class does not accept the instance of LoginService via dependency injection.
Next, we have our LoginService class that we are going to mock (stripped for this post):
public
class
LoginService
{
public
int
ValidateUser(
string
userName,
string
password)
{
int
userID = 5;
return
userID;
}
}
Moving forward, JustMock does not require any extra construct to mock future objects. Therefore, we can simply write our test in the following way:
[TestMethod]
public
void
Should_Assert_Behavior_On_Concrete_Class()
{
string
userName =
"User"
;
string
password =
"Pwd"
;
bool
asserted =
false
;
LoginService service =
new
LoginService();
Mock.Arrange(() => service.ValidateUser(userName, password)).DoInstead(() => asserted =
true
);
var sut =
new
LegacyCode();
sut.CheckUser(userName, password);
Assert.IsTrue(asserted);
Mock.Assert(service);
}
Since we have simply created the instance, the test will work if the method is either final or virtual. But if we create a mocked instance via Mock.Create<LoginService>() then it will only work if the method is final because Mock.Create builds proxied instance for non-sealed classes and therefore initializes the virtual methods via proxy (simpler and faster than profiler).
Overall, if you want to create future objects simply create the instance of the target class via new keyword in that regard there is no need to do Mock.Create<T> unless it is sealed.
Finally, I have attached the test project to let you have a look and please do feel free to write us back for any further issues.
P.S. The post applies to commercial edition only (also can be tested using the trial build)
Kind Regards,
Ricky
the Telerik team
Thanks again for the post. Regarding "Mocking future object", as it is done through profiler that is not free therefore you can't do that in the free version. For free version the only way is to send the mocked object via dependency injection.
Should you have any more issues, please don’t hesitate to contact us.
Ricky
the Telerik team
I now have the full version of JustMock (not the free edition) which I got with the MS MVP offer from telerik. The exemple above sent as an attachment still fails... One thing I'm wondering is this:
The "Arrange" line, under the covers, is it saying replace the call to ValidateUser IN ALL FUTURE INSTANCES of type LoginService or does it ONLY apply to the instance used in the arrange statement (local variable of the unit test) ?
I thought it would only apply to the instance of LoginService used in the arrange statement which is local to the unit test and would therefore be sort of useless in my case....
I'm still without luck on this issue... I run the Unit Test that was provided in this post without success...
So I guess this confirms the Arrange applies to all future instances of a type...
Thanks for your time!
In the sample presented above, we replace the call to ValidateUser in the LoginService with a lambda that flags a bool to True.... That I understand... My original question was related to the creation of future objects...
How would I proceed to make sure that the CONSTRUCTOR for the LoginService is NEVER CALLED.... Suppose that the LoginService constructor does some evil thing and we do not want this line to be executed:
public class LegacyCode
{
public int CheckUser(string userName, string password)
{
----> LoginService _service = new LoginService();
return _service.ValidateUser(userName, password);
}
}
... and instead, the _service variable is loaded with a predefined LoginService MOCK. How can I accomplish this?
I would assume this would be done using some sort of arrange but not on the future method calls of the instance but an arrange on the creation of the object itself.... Any ideas?
What I want is a way to tell the mocking framework: "Whenever you see an object of type X created, replace the creation (call to the constructor and all) with this Mock"...
Any chance this can be done with JustMock?
Hi Vincent,
Thanks again for making the post.
As we are keeping things as explicit as possible therefore using JustMock to create a mocked object you must need to use Mock.Create or less it will be like a normal create new. Therefore, there won’t be any hidden replace via profiler. This actually eliminates ambiguity and thus makes things simpler.
However, when you create a mocked instance using Mock.Create, it calls the default constructor or the specific constructor based on the arguments passed in or constructor mentioned via lambda (Similar to Moq / Rhino).
Although for class with no default constructor, Mock.Create does create the instance without calling any constructor. But in your case, if LoginService has a default constructor then for that i am adding a task that will give you an additional option whether to mock the constructor when creating the instance via Mock.Create.
You can further track the issue here:
http://www.telerik.com/support/pits.aspx#/public/justmock/4608
Finally, hope that answers your question and please do feel free to write back for any other issues.
Kind regards,
Ricky
the Telerik team
I made a reply to your ticket # 630799 regarding this issue. Please check it out.
Ricky
the Telerik team
Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.
This sounds like exactly what I need, but I am not able to get it to work. In my scenario. I am testing a method that creates a new object, and calls a method on that object.
It's something similar to this scenario:
public
SampleClass() {
public
int
Number1 {
get
;
set
;}
public
int
Number2 {
get
;
set
;}
public
int
DoMath() {
return
Number1 + Number2;
}
}
The code I'm testing would be similar to this:
public
int
TestMethod() {
var someModel =
new
SampleClass { Number1 = 2, Number2 = 3 };
someModel.DoMath();
// Other code
return
someNumber;
}
My TestMethod creates a new instance of SampleClass and the uses Mock.Arrange() to mock the DoMath() method, but it is not working.
Any advice?
My TestMethod creates a new instance of SampleClass and the uses Mock.Arrange() to mock the DoMath() method, but it is not working.Any advice?
Can you give me the test method's code? I'd like to see what your arrangements and assertions look like. Also, can you explain how it's not working? Does it fail with an exception? Does it behave as if it weren't mocked at all?
Thank you for your patience.
Regards,
Stefan
Telerik
Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.
Here's the Test Code:
// Arrange
var request =
new
CohesionRequest();
var calledCohesion =
false
;
Mock.Arrange(() => request.MakeCoreRequest(Arg.IsAny<
string
>(), Arg.IsAny<
bool
>()))
.DoInstead(() => { calledCohesion =
true
; })
.OccursOnce();
// Act
this
.loanService.GetLoanTransferRecords(
"AP"
,
"1234"
);
// Assert
Assert.IsTrue(calledCohesion);
Your arrangement as it is works only on the "request" instance. As I understand, the system under test creates and uses a different instance internally. For the arrangement to have an effect on all instances, you must add the .IgnoreInstance() clause, like so:
Mock.Arrange(() => request.MakeCoreRequest(Arg.IsAny<
string
>(), Arg.IsAny<
bool
>()))
.IgnoreInstance()
.DoInstead(() => { calledCohesion =
true
; })
.OccursOnce();
Alternatively, you can use the following syntax:
Mock.Arrange(() => Arg.IsAny<CohesionRequest>().MakeCoreRequest(Arg.IsAny<
string
>(), Arg.IsAny<
bool
>()))
.DoInstead(() => { calledCohesion =
true
; })
.OccursOnce();
When there's an arrangement that looks like it should work, but doesn't, you can debug it using the handy DebugView feature of JustMock.
Let me know if you're still having trouble.
Regards,
Stefan
Telerik
Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.
That worked, thank you so much. I just have one clarifying question: In Ricky's post at the top of this thread in response to the original question he didn't have to use IgnoreInstance or Mock using Arg.IsAny<>
I'm just curious what was different between the original question and my code that prevented the answer at the top from working for me.
Thanks again,
Andrew
The initial reply from my colleague is rather old. Since then, there are changes that have been applied to the JustMock api.
Now, you can check this article from the online documentation in order to follow the correct guidelines about mocking future objects with JustMock. I hope it helps.
Regards,
Kaloyan
Telerik
Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.