As promised, albiet with slight delay, we released version 5.3 today. The major features are:
- Exact argument matching when setting behavior
- A new DoInstead() completing statement allows setting dynamic behavior
- Better control of constructor behavior when creating fakes
- Solves many issues with generics support (for "object" and others...)
This is the first version we've released while using this blog as a sounding stage for our ideas, suggestions and plans. Your input has been invaluable - thank you all!
Please let us know of any feedback on this version. I'll continue updating this blog with our feature plan for upcoming versions.
Generics work much better now. But there is still one test that fails (actually only one of my tests failed this time). I've posted a bug in the "Bugs" forum:
ReplyDeletehttp://www.typemock.com/community/viewtopic.php?t=1236
Not related to this particular version, but it's so annoying it's not possible to hide "ToString" and others from intellisense.. It would have made the API look much nicer!
ReplyDeleteIt seems EditorBrowsable does not work AT ALL - both from source code and metadata (although they claim that metadata is ok - http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=105485)
Has anyone in Typemock looked into the issue?
Is it possible to make DoInstead generic so that context.Instance is not just object?
ReplyDeleteHowever, the original example (about "MyProduct" count) looks contrived. Does anyone has anything better in mind?
(For now, DoInstead looks like a tool for writing VERY confusing and overspecified tests and should be used VERY rarely.)
Andrew,
ReplyDeleteWe tried it and I think that it is not possible to pass the type of the fake (think chains) to the DoInstead method.
Do you have any ideas on how we can do this?
Eli, sorry for the delayed reply - no, I have no concrete idea.
ReplyDeleteI was thinking of a DoInstead{T} method where the generic part may o may not be guessed by the compiler. Chaining probably means users would need to explicitly specify the T.
The problem with this is that the C# compiler can infer the T on DoInstead«T»() based on the return type of member being faked – WhenCalled«T» and not on the instance being faked.
ReplyDeleteUnfortunately, the C# compiler can’t infer types from a partial list of type parameters. The compile can’t infer DoInstead«T, U» from DoInstead«U». So, you can’t write:
Isolate.WhenCalled(() =» fake.IntCallWithArgs(0))
.DoInstead«RealLogger»((callContext) =»
{
callContext.Instance.count = (int)callContext.Parameters[0];
return 100;
});
You would have to write:
Isolate.WhenCalled(() =» fake.IntCallWithArgs(0))
.DoInstead«int, RealLogger»((callContext) =»
{
callContext.Instance.count = (int)callContext.Parameters[0];
return 100;
});
Or change the API in order for WhenCalled«T»(Func«T») to become WhenCalled«U, T»(U, Func«U,T»). Then, the test would be written as:
Isolate.WhenCalled(fake, (fake) =» fake.IntCallWithArgs(0))
.DoInstead«int, RealLogger»((callContext) =»
{
callContext.Instance.count = (int)callContext.Parameters[0];
return 100;
});
You can always create an extension method like this:
public T As«T»(this object self) { return self as T; }
and instead of ((RealLogger)callContext.Instance).count, you would have callContext.Instance.As«RealLogger»().count.
One can always hope for having generic properties in the future: callContext.Instance«RealLogger».count.
The instance could have been a method instead: callContext.GetInstance«RealLogger»().count. But if there’s a use case where I don’t have any doubts whether to use a property or a method is this one.
So, who’s not convinced that this is the best implementation? :)