This is a migrated thread and some comments may be shown as answers.

Mock.Create fails on some real objects

7 Answers 148 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Justin Dority
Top achievements
Rank 1
Justin Dority asked on 14 Jul 2010, 02:51 PM
I'm working on a test case against a static method that makes a few calls on an object, and I'm trying to make those calls do nothing.  The issue I'm having is that this:

TransactionHeaderViewModel

 

ticket = Mock.Create<TransactionHeaderViewModel>();

 


fails with the following:
Test method POSUnitTests.TransactionServiceTest.SaveTransactionTest threw exception:  System.NullReferenceException: Object reference not set to an instance of an object..

Telerik.JustMock.DynamicProxy.MethodInvocation.Continue() in c:\B\Basilisk\Basilisk CI Build\Sources\CodeBase\Telerik.JustMock\DynamicProxy\MethodInvocation.cs: line 150
Intercept(IInvocation invocation) in c:\B\Basilisk\Basilisk CI Build\Sources\CodeBase\Telerik.JustMock\Interceptors\ProxyInterceptor.cs: line 35
TransactionHeaderViewModel_Proxy_a39192a5eca04cbbb79efb55f2387785.GetHashCode(MethodInvocation , Int32 , Boolean )
TransactionHeaderViewModel_Proxy_a39192a5eca04cbbb79efb55f2387785.GetHashCode()
get_Instance() in c:\B\Basilisk\Basilisk CI Build\Sources\CodeBase\Telerik.JustMock\MockObject.cs: line 44
Telerik.JustMock.Mock.Create(Type target, BehaviorMode mode, Object[] args) in c:\B\Basilisk\Basilisk CI Build\Sources\CodeBase\Telerik.JustMock\Mock.cs: line 354
Telerik.JustMock.Mock.Create(Type target, Object[] args) in c:\B\Basilisk\Basilisk CI Build\Sources\CodeBase\Telerik.JustMock\Mock.cs: line 339
Telerik.JustMock.Mock.Create[T]() in c:\B\Basilisk\Basilisk CI Build\Sources\CodeBase\Telerik.JustMock\Mock.cs: line 328
POSUnitTests.TransactionServiceTest.SaveTransactionTest() in c:\tfs\Point of Sale\POSApp\Main\Source\POSUnitTests\TransactionServiceTest.cs: line 151


If I just do a TransactionHeaderViewModel ticket = new TransactionHeaderViewModel(); instead, then the calls to Mock.Arrange(() => ticket.SetLineNumbers()).DoNothing(); don't actually work, when debugging the test case you can see that the actual code is called.  I also tried making SetLineNumbers() a virtual, but that caused the "Opps" error.

I thought that it was having an issue with what the constructor was doing, so I commented out everything in the constructor, but still get the same error (in fact, the error above is from that simplified case).

Any thoughts, or is this something that's already fixed in the current builds?  I'm on the 528.5 beta release.


Thanks,
     Justin

7 Answers, 1 is accepted

Sort by
0
Chris
Telerik team
answered on 14 Jul 2010, 03:08 PM
Hello Justin,

The official Q2 2010 version has just been released. Could you please download it and try this with the latest version?

Regards,
Chris
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Justin Dority
Top achievements
Rank 1
answered on 14 Jul 2010, 05:48 PM
Thanks, that seems to work now, but I now have another issue.  I'm setting up a static property and method to return specific values like this:

 

Mock.Arrange(() => UserService.Username).Returns("testUser");

 

 

Mock.Arrange(() => UserService.GetLoggedInUser()).Returns(new BBA.POS.Data.Settings.POSUser() { UserId = "testUser" });

 

 

Mock.Arrange(() => ConfigurationService.GetConfiguration()).Returns(new BBA.POS.Data.Settings.TerminalSettings() { TerminalNumber = 5 });

 

 

These used to work in the beta version, but now only the UserService.Username property returns what was arranged.  The two static methods both run the original version (and consequently return null).  Did something change so I'm missing a step now?

Thanks,

     Justin

0
Ricky
Telerik team
answered on 15 Jul 2010, 11:26 AM
Hi Justin,
There was a little issue regarding type loading that I fixed just after the release and will be available in the next build. To reproduce the issue, I wrote a similar test from that you have shown here. Let me know, if it correctly covers your case so that we are on the right page.

[TestMethod]
public void ShouldAssertMultipleStaticSetups()
{
    Mock.Arrange(() => UserServices.UserName).Returns("Justin");
    Mock.Arrange(() => UserServices.GetLogginUser()).Returns(new User());
    Mock.Arrange(() => UserServices.GetConfiguration()).Returns(new Configuration());
    Assert.Equal("Justin", UserServices.UserName);
    Assert.NotNull(UserServices.GetLogginUser());
    Assert.NotNull(UserServices.GetConfiguration());
}
public class UserServices
{
    public static string UserName { get; set; }
    public static User GetLogginUser()
    {
        return null;
    }
    public static Configuration GetConfiguration()
    {
        return null;
    }
}
public class User
{
}
public class Configuration
{
}

Finally, to avoid the issue with current build, I would suggest splitting up the test into three test methods that deals with those calls separetly.

Kind regards,
Mehfuz
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Justin Dority
Top achievements
Rank 1
answered on 15 Jul 2010, 01:44 PM
Thanks, I'll try the next build when I get a chance.  The static property (UserServices.UserName in that example) works, but the static methods don't.  The test case in question is one for another static method that uses all of these, the full code of the test method is:

[TestMethod()]
public void SaveTransactionTest()
{
    TransactionHeaderViewModel ticket = Mock.Create<TransactionHeaderViewModel>();
    bool recalculate = false;
    Random r = new Random();
    int resNumber = r.Next(9999);
    Mock.Arrange(() => UserService.Username).Returns("testUser");
    Mock.Arrange(() => UserService.GetLoggedInUser()).Returns(new BBA.POS.Data.Settings.POSUser() { UserId = "testUser" });
    Mock.Arrange(() => ConfigurationService.GetConfiguration()).Returns(new BBA.POS.Data.Settings.TerminalSettings() { TerminalNumber = 5 });
    // Now set up the transaction save calls
    Mock.Arrange(() => TransactionService.RecalculateTicket(Arg.IsAny<TransactionHeaderViewModel>())).IgnoreArguments().DoNothing();
    Mock.Arrange(() => ticket.SetLineNumbers()).DoNothing();
    Mock.Arrange(() => ticket.SetPaidAmount()).DoNothing();
    Mock.Arrange(() => ticket.SaveTicket()).DoNothing();
    Mock.Arrange(() => TransactionService.GetReservationNumber(Arg.IsAny<string>())).IgnoreArguments().Returns(resNumber);
    // Check that RecalculateTicket was not called, but the others were, and operatorId is still null
    TransactionService.SaveTransaction(ticket, recalculate);
    Mock.Assert(() => TransactionService.RecalculateTicket(Arg.IsAny<TransactionHeaderViewModel>()), Occurs.Never());
    Mock.Assert(() => TransactionService.GetReservationNumber(Arg.IsAny<string>()), Occurs.Once());
    Mock.Assert(() => ticket.SetLineNumbers(), Occurs.Once());
    Mock.Assert(() => ticket.SetPaidAmount(), Occurs.Once());
    Mock.Assert(() => ticket.SaveTicket(), Occurs.Once());
    Assert.Equals(ticket.ReservationNumber, resNumber);
    Assert.IsTrue(string.IsNullOrEmpty(ticket.OperatorId));
}

The problem is that it's blowing up with a NullReferenceException due to the UserService.GetLoggedInUser() call returning null inside the TransactionService.SaveTransaction call.

If I've missed something simple in there, let me know, otherwise, I'll wait for the next build to be released.


Thanks,

     Justin
0
Ricky
Telerik team
answered on 16 Jul 2010, 09:05 AM
Hi Justin,

Thanks for the test method. Looking at your test closely, I found few issues and  wrote the test in the following way :

TransactionHeaderViewModel ticket = Mock.Create<TransactionHeaderViewModel>(Behavior.CallOriginal);
bool recalculate = false;
Random r = new Random();
int resNumber = r.Next(9999);
Mock.Arrange(() => UserService.Username).Returns("testUser");
Mock.Arrange(() => UserService.GetLoggedInUser()).Returns(new User());
Mock.Arrange(() => ConfigurationService.GetConfiguration()).Returns(new Configuration());
// Now set up the transaction save calls 
Mock.Arrange(() => TransactionService.RecalculateTicket(null)).IgnoreArguments().DoNothing();
Mock.Arrange(() => ticket.SetLineNumbers()).DoNothing();
Mock.Arrange(() => ticket.SetPaidAmount()).DoNothing();
Mock.Arrange(() => ticket.SaveTicket()).DoNothing();
Mock.Arrange(() => TransactionService.GetReservationNumber("")).IgnoreArguments().Returns(resNumber);
// Check that RecalculateTicket was not called, but the others were, and operatorId is still null 
TransactionService.SaveTransaction(ticket, recalculate);
Mock.Assert(() => TransactionService.RecalculateTicket(Arg.IsAny<TransactionHeaderViewModel>()), Occurs.Never());
Mock.Assert(() => TransactionService.GetReservationNumber(Arg.IsAny<string>()), Occurs.Once());
Mock.Assert(() => ticket.SetLineNumbers(), Occurs.Once());
Mock.Assert(() => ticket.SetPaidAmount(), Occurs.Once());
Mock.Assert(() => ticket.SaveTicket(), Occurs.Once());
Assert.AreEqual(ticket.ReservationNumber, resNumber);
Assert.IsTrue(string.IsNullOrEmpty(ticket.OperatorId));

Instead of :
TransactionHeaderViewModel ticket = Mock.Create<TransactionHeaderViewModel>();

I added this :
TransactionHeaderViewModel ticket = Mock.Create<TransactionHeaderViewModel>(Behavior.CallOriginal);

Note that i added Behavior.CallOriginal that means by default it will invoke the original method unless otherwise specified using Mock.Arrange as you have this lines at the end:


Assert.AreEqual(ticket.ReservationNumber, resNumber);
Assert.IsTrue(string.IsNullOrEmpty(ticket.OperatorId));


The properties ReservationNumber and OperationId and is set directly in SaveTicket function without any setup and finally, you asserted the values as if in the original object.  For other other cases,  you have Mock.Arrange so better to put Behavior.CallOriginal.

Secondly, I modified :

Mock.Arrange(() => TransactionService.RecalculateTicket(Arg.IsAny<TransactionHeaderViewModel>())).IgnoreArguments().DoNothing(); 
  
// And
Mock.Arrange(() => TransactionService.GetReservationNumber(Arg.IsAny<string>())).IgnoreArguments().Returns(resNumber);


To more simpler :

Mock.Arrange(() => TransactionService.RecalculateTicket(null)).IgnoreArguments().DoNothing(); 
  
// And
Mock.Arrange(() => TransactionService.GetReservationNumber("")).IgnoreArguments().Returns(resNumber);


As, you are using IgnoreArguments, you don't need the extra Arg.IsAny as you are specifying to ignore the arguments anyway.

Finally, I reproduced the test and ran it in my local machine with the trial build from justmock download page and i found the test is passing. Make sure that you throw proper exception for UserService.Username and your elevated tests in the supplied examples passing.

I am also attaching the file, let me know if that passes for you and feel to modify the class structure and send me back in case of failure.

Regards,
Mehfuz


Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Justin Dority
Top achievements
Rank 1
answered on 16 Jul 2010, 04:06 PM
Thanks Mehfuz, I think we're on the right track.  The solution you attached works fine for me in both VS 2010 and VS 2008, but the changes to my real project didn't resolve the issue, one of the static methods is still returning null instead of the Arrange() value.  I changed the project around a bit to move the data and services to separate classes as they are in my real project.  When I moved the data classes, it still worked fine, but after I moved the service classes, the test failed because the ConfigurationService.GetConfiguration() call returned null (the real code result) instead of a new Configuration (the Arrange() result).

I have attached that solution to support ticket #328879.
0
Accepted
Ricky
Telerik team
answered on 19 Jul 2010, 04:00 PM

Hi Justin,

There is an answer posted to the ticket # 328879 that deals with this issue, please check it out.

Regards,
Mehfuz


Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Tags
General Discussions
Asked by
Justin Dority
Top achievements
Rank 1
Answers by
Chris
Telerik team
Justin Dority
Top achievements
Rank 1
Ricky
Telerik team
Share this question
or