chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes
Class:
* BaseClass is an Abstract Class.
class DerivedClass : BaseClass
{
 protected override void MethodA(List<ClassX> exceptionIds)
 {

  if(string.IsNullOrEmpty(this.PropertyX))
  {
    exceptionIds.Add(new ClassX("SignatureToMatch");
  }
  else
  {
    exceptionIds.Add(new ClassX("DifferentSignature");
  }

  base.MethodA(exceptionIds);
 }
}


Test Class:
class DerivedClassTest
{
 [TestMethod(), VerifyMocks()]
 public void MethodATest()
 { 
  MockObject mockObject = MockManager.MockObject<DerivedClass>();
  DerivedClass target = (DerivedClass)mockObject.Object;
  mockObject.ExpectGetAlways("PropertyX", string.Empty);

  List<ClassX> exceptionIds = new List<ClassX>();
  exceptionIds.Add(new ClassX("SignatureToMatch"));

mockObject.CallBase.ExpectCall("MethodA").Args(TypeMock.Check.IsSame(exceptionIds));
  target.PublicAccessorMethodForMethodA();
 }
}


*TypeMock.Check.IsEqual fails too, as both are different instances.

When I try to mock the base class with following code,
'mockObject.CallBase.ExpectCall("MethodA").When(exceptions);'
and I debug the test, I see that the call to base class mathod 'MethodA' is surrounded by a maroon rectangle, which usually is a sign for a codeblock to be mocked. But, in this case the execution flows as normal and the code block for BaseClass's 'MethodA' is not mocked. Also, in this case, arguments are not varified. in other words, call to the baseclass method is made (and not mocked) whether the passed argument is correct or not.

If arguments are not verified, i.e. 'mockObject.CallBase.ExpectCall("MethodA")' mocks the base class call successfully. After appending '.Args(TypeMock.Check.IsSame(exceptionIds));', test fails with the exception

TypeMock.VerifyException: 
TypeMock Verification: Call to BaseClass.MethodA() Parameter: 1
passed object [System.Collections.Generic.List`1[ClassX]] is not the same as expected [System.Collections.Generic.List`1[ClassX]].


P.S.: I wonder whether we can mock BaseClass calls using NaturalMocks.
Note: I have found work around for this situation, but I might encounter such situation in future and wanted to report this to TypeMock.
asked by vikaschoithani (2.8k points)

6 Answers

0 votes
Hi Vikas,

I am looking into your question and will get back to you with a reply in this forum. In the meanwhile, please post your workaround here for other people who may encounter the same issue.

Thanks,
Doron
Typemock Support
answered by doron (17.2k points)
0 votes
Hi Doron,

Thanks for the prompt reply.
Here's what I am doing. Instead of calling the base class only if arguments match, I am just calling it without any check. Then I am checking if the new created object of 'ClassX' was created with right arguments.
I encounter one little problem while doing this. Since I am calling 'MethodA'(i.e. the method I am trying to test) using a 'PublicAccessorMethodForMethodA', which is a public method in the BaseClass. 'PublicAccessorMethodForMethodA' calls some method(i.e. 'CallToSomeOtherMethod_InClassX_FailsIfThisCallIsNotMoacked') from ClassX, which reads a [local variable] that gets initialised in constructor.
Since in the case depicated below, I am mocking a constructor call to 'ClassX', this [local variable] doesn't get initialised and throws an exception during the call to 'CallToSomeOtherMethod_InClassX_FailsIfThisCallIsNotMoacked'(which is internally called from 'PublicAccessorMethodForMethodA').

So, I am not really satisfied with the workaround I have here. But, until a better solution is suggested, this works pretty fine against the scenario mentioned.

The Work around code is as below:

public void MethodATest()
{ 
  MockObject mockObject = MockManager.MockObject<DerivedClass>();
  DerivedClass target = (DerivedClass)mockObject.Object;
  mockObject.ExpectGetAlways("PropertyX", string.Empty);

  mockObject.CallBase.ExpectCall("MethodA");

  Mock mock = MockManager.Mock<ClassX>();
  mock.ExpectConstructor().Args(new object[] { "SignatureToMatch"});
   mock.ExpectCall("CallToSomeOtherMethod_InClassX_FailsIfThisCallIsNotMoacked");
  target.PublicAccessorMethodForMethodA();
}


-Vikas
answered by vikaschoithani (2.8k points)
0 votes
Hi Doron,

Following up with you regarding the issue I posted.

Thank you,
-Vikas
answered by vikaschoithani (2.8k points)
0 votes
Hi Vikas

Try to replace Check.IsSame with Check.CustomChecker and than supplay your own custom checker. Note that Check.IsSame will check if the references are equal which is not the case in your code.

Try something like this:

[Test]
public void MethodATest()
{
    MockObject mockObject = MockManager.MockObject<DerivedClass>();
    DerivedClass target = (DerivedClass)mockObject.Object;
    mockObject.ExpectGetAlways("PropertyX", string.Empty);

    List<ClassX> exceptionIds = new List<ClassX>();
    exceptionIds.Add(new ClassX("SignatureToMatch"));    
    mockObject.CallBase.ExpectCall("MethodA").Args(Check.CustomChecker(new ParameterCheckerEx(CheckParams), exceptionIds));
    target.PublicAccessorMethodForMethodA(); 
}

//your custom arguments checker method
private bool CheckParams(ParameterCheckerEventArgs data)
{
    List<ClassX> actual = data.ArgumentValue as List<ClassX>;
    return actual[0].ClassXString == "SignatureToMatch";
}


Hope it helps and sorry for the late reply :oops:
answered by ohad (35.4k points)
0 votes
Hi Doron,

Thanks for the reply. The solution you suggested worked fine.
However, I am still not clear on how ‘IsEqual’ differs from ‘IsSame’, if both check against the instance of the expected and actual parameter.

-Vikas
answered by vikaschoithani (2.8k points)
0 votes
Hi Vikas

The difference is that IsEqual calls the object's Equal method while IsSame
checks if the references are same.
So IsEqual result depends if the type overrides the Equals method. If not the base class implementation will be called.

I think that our documentation is not clear in this case. We will fix
that in next version.

Thanks for your input 8)
answered by ohad (35.4k points)
...