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
Consider a class that creates an internal dependency object and passes a delegate to be used for callback into the constructor. In order to test that this class responds properly to the callback, I need to invoke the callback during the test. How can I access the callback delegate that was passed in the construction?


class Dependency {
public Dependency(Action callback) {
//starts asynchronous operation that leads to callback being called later
}
}

class MyClass {
Dependency dependency;

public void Method() {
dependency = new Dependency(Callback);
...
}

void Callback() {
...
}
}


[TestFixture]
class TestMyClass {
[Test]
public void TestCallbackResponse() {
var fakeDependency = Isolate.Fake.Instance<Dependency>();
Isolate.Swap.NextInstance<Dependency>().With(fakeDependency);

var objectUnderTest = new MyClass();
objectUnderTest.Method();

//invoke callback ... how?

//verify: asserts on objectUnderTest
}
}
asked by WoodwardDev (680 points)

6 Answers

0 votes
Hi Paul,

As Alex mentioned in his mail, Isolator provides APIs for method invocations and verifications. You can find documentation on both in the following URLs:

Invocation

Verification

Additional information can be found in the cookbook.


As for your example, there are some missing details:
1) Do you want to invoke the callback on fakeDependency or objectUnderTest?

2) Do you store the callback in a field inside Dependency?

3) In order to assert on objectUnderTest I have to know what it does.

If you can send a small project that shows the issue in details, I'll be happy to find a solution for this problem.
answered by NofarC (4k points)
0 votes
Thank you for your response.

As there are numerous instances of this callback pattern in the program I work on, I have left out specific details that may vary. I'm looking for a general solution to a general problem.

Here are answers to your questions:
1. I want to invoke the delegate that has been passed to the Dependency constructor. This is preferred over calling the private Callback method directly using reflection.
2. The callback delegate may be stored in a field within Dependency or stored in an object that Dependency references. This is an implementation detail that I would prefer that the tests not depend on.
3. Verifying the object under test once the callback delegate has been invoked is not an issue. In some cases the public state of the object under test changes and in other cases an event is fired. Either way, I know what to do to verify the object.

A specific example of a Dependency-like class is the System.Threading.Timer class. It's constructor takes a delegate that is invoked when the specified interval has elapsed. How would you test the timer elapsed response of a class that uses an object of this type?

Regards,
Paul
answered by WoodwardDev (680 points)
0 votes
Hi Paul,

If I understand correctly what your're trying to do you need to:
1. Create a fake instance of the dependency by using the Isolate.Fake.NextInstance API
2. Invoke the callback by using the Isolate.Invoke API.


If it's not the direction you are going to, please let me know.
answered by NofarC (4k points)
0 votes
Hello Nofar,

I would like to intercept the call to the dependency constructor so that I can store the delegate that has been passed in order to invoke it later in the test.

Using Isolator’s legacy API I can do this:

[Test]
public void TestCallbackResponse() {
Action callback = null;
var dependencyMock = MockManager.Mock<Dependency>(_connectOperation);
dependencyMock.ExpectConstructor().Args((ParameterCheckerEx) ((args) => {
callback = args.ArgumentValue as Action;
return callback != null;
}));

var objectUnderTest = new MyClass();
objectUnderTest.Method();

callback();

//verify: appropriate asserts on objectUnderTest
}

While TypeMock still includes this legacy API in the library, the newer API is much more usable, especially when we need to fake other methods on the dependency. Also, the legacy API isn’t discussed much in the Isolator documentation, and it looks as though you are phasing it out or at least not promoting it.

So, how should I test this with Isolator’s current API?

Using Isolator.Invoke to call the private callback method bypasses and therefore doesn’t test part of the code. I prefer to intercept the constructor call and invoke the callback through the passed-in delegate.
answered by WoodwardDev (680 points)
0 votes
Hi,

We do encourage to use the new API as it is more intuitive and straightforward.
However, it is not as powerful as the legacy one, and what you are interested in is one of the few kinds of interception that the new API does not support.

We'll consider adding this ability to the new API in the future versions.
Luckily you already have a workaround using the legacy API.

legacy API isn’t discussed much in the Isolator documentation
Thank you for raising this point.
I have to agree that the legacy API is not documented as well as the new one.
But, it is available both on our site and in the help file in the installation folder.
answered by alex (17k points)
0 votes
Hi Paul,

We added this ability in our new version.

You can try it now:)
answered by Bar (3.3k points)
...