0

I have a unit test. When I define call back function for the setup of my function of the interface and call Verify on the call Moq throws NullReferenceException exception that I am really puzzled by.

Update: I forgot to mention important part. When I run tests one by one all works fine but when I run all the tests this test fails.

Exception:

System.NullReferenceException : Object reference not set to an instance of an object.
   at Moq.MethodCall.Matches(ICallContext call)
   at System.Linq.Enumerable.WhereListIterator`1.MoveNext()
   at System.Linq.Enumerable.Count[TSource](IEnumerable`1 source)
   at Moq.Mock.VerifyCalls(Interceptor targetInterceptor, MethodCall expected, Expression expression, Times times)
   at Moq.Mock.Verify[T](Mock mock, Expression`1 expression, Times times, String failMessage)
   at Moq.Mock`1.Verify(Expression`1 expression, Times times)
   at LimitTest.LimitEditor.LimitEditorTest.EditActionSetExistingLimit(Boolean add) in

Unit test:

var io= new Mock<ILimitServiceIO>(MockBehavior.Strict);
var LimitServiceIO= new MemoryLimitServiceIO();

... different setups...

io.Setup(x => x.PersistActionSet(It.Is<string>(id=>id==companyId), It.IsAny<IList<CsiNotificationActionSet>>()))
                .Callback((string compid, IList<CsiNotificationActionSet> sets) =>LimitServiceIO.PersistActionSet(compid, sets));

... Do some actions...

//This line throws exception
mockIo.Verify(x => x.PersistActionSet(measure.CompanyId,
            It.IsAny<IList<CsiNotificationActionSet>>()), Times.Once());

Assert.AreEqual(2,LimitServiceIO.ActionSets.First(acs => acs.Id == ACTION_SET_A1).Actions.Count,
                "Number of Actions does not match");

The signature of PersistActionSet method is:

void PersistActionSet(string companyId, IList<CsiNotificationActionSet> actionSets)

Any ideas why it happens or pointers are appreciated very much.

Old Fox
  • 8,629
  • 4
  • 34
  • 52
Tech Wizard
  • 403
  • 2
  • 7
  • 22
  • Can you show us the signature for the original `PersistActionSet` you are overriding? – zaitsman Jul 17 '18 at 13:53
  • Also, you seem to be missing `.Verifiable()` before `Callback` – zaitsman Jul 17 '18 at 13:53
  • @zaitsman This the is signature: void PersistActionSet(string companyId, IList actionSets); Not really overriding anything only implementation – Tech Wizard Jul 17 '18 at 15:49
  • 1
    @zaitsman why .Verifiable() before Callback is needed? – Tech Wizard Jul 17 '18 at 15:49
  • What version of moq do you use? In the past moq had a thread safe problem... It seems that `mockIo` just forward the calls to `LimitServiceIO`, why do you use `mockIo` at all? Please add a complete code so I'll be able to point out the reason for the null pointer exception... BTW in most cases using a strict mock is a bad practice and it seems that you have mixture in the style of the verification(strict mock, loose mock verification and real object...) – Old Fox Jul 17 '18 at 22:05
  • 1
    @OldFox Moq version is 4.8.2, I use mockIo in order to verify calls. LimitServiceIO has hard coded objects, that in reality will be retrieved. Complete code is a lot of code so trying to give the most important. why strict mock is a bad practice, any pointers/articles on better practice? – Tech Wizard Jul 18 '18 at 08:38
  • @AlexanderGurevich basically the reason it counts as a bad practice is because your UT become depended on the implementation instead of verifying a specific behavior. This might lead to UTs to fail while there specific verification was not break at all. In [this question](https://stackoverflow.com/a/50763837/4332059) the OP had a problem because he used `strict mock`. Without a complete code where I'll be able to reproduce your situation locally I won't be able to help fixing the problem... – Old Fox Jul 18 '18 at 13:32

2 Answers2

2

Also posting for posterity since I've had this problem a few times as well now, and none of the results from Google solve the issue for me.

If we have a mock object of some class with a method public string Foo(string s) and we want to do something with the parameter passed to this method, all of the results I have found say you need to use a callback like this:

mockObject.Setup(m => m.Foo(It.IsAny<string>()))
    .Callback<string>((s) => { /* Do something with parameter s */ });

but that gives a NullReferenceException. What solves the problem for me is adding a Returns() before the Callback():

mockObject.Setup(m => m.Foo(It.IsAny<string>()))
    .Returns("bar")
    .Callback<string>((s) => { /* Do something with parameter s */ });
J. Barkema
  • 21
  • 4
0

For posterity and other people running into weird errors out of the blue. Setting STAThread attribute on the test solved the issue

Tech Wizard
  • 403
  • 2
  • 7
  • 22