Welcome to Typemock Answers. Here you can ask and receive answers from other community members. And if you liked or disliked an answer or thread: react with an up- or downvote Enjoy!

Failure Method 'Add' on type ...... not visible from that ..

+1 vote
I have the following code, that is trying to mock a certain MS Sharepoint object:

using Microsoft.SharePoint.Workflow;
using NUnit.Framework;
using TypeMock;
[Test]
public void Test()
{
MockManager.Init();
MockObject spWFAssocs = MockManager.MockObject(typeof(SPWorkflowAssociationCollection));
spWFAssocs.ExpectGetAlways("get_Count", 0);
MockManager.Verify();
}

When I execute this test code I get this error:


failed: System.TypeLoadException : Method 'Add' on type 'MockSPWorkflowAssociationCollection' from assembly 'DynamicMockAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is overriding a method that is not visible from that assembly.
at System.Reflection.Emit.TypeBuilder.TermCreateClass(Int32 handle, Module module)
at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
at System.Reflection.Emit.TypeBuilder.CreateType()
at u.a(Type A_0, Object[] A_1)
at TypeMock.MockManager.MockObject(Type type, Constructor mockConstructors, Object[] args)
at TypeMock.MockManager.MockObject(Type type, Object[] args)


Any inside to this error, or any workarounds? I quickly tried using Mock instead of MockObject, it didn't give the error, but I may need to use MockObject to be able to mock different instance differently. I have TypeMock 3.7.1 installed currently.

TIA
asked Jun 19, 2007 by phazer (850 points)

10 Answers

+1 vote
I have been able to isolate and replicate the problem, the cause is that the class that is being mocked is abstract, and has an abstract method which "internal", not visible to outside.

I compiled this simple class in a separate assembly:

public abstract class Class1
{
private int _m;
protected Class1()
{
_m = 55;
}
internal abstract void InternalAbstractMethod();
public int ReturnInt()
{
return _m;
}
}

When I tried to mock it from another assembly, with the following code:

MockObject mockObj = MockManager.MockObject(typeof (Class1));

I get the same failure error when the code is executed, as I mentioned in the above post.

So in short, mocking abstract classes that have internal abstract methods is causing failure. Is this a known issue? Is there any workarounds?

Thanks
answered Jun 19, 2007 by phazer (850 points)
0 votes
Hi,
Thanks for the detailed report. Currently .NET doesn't allow extending internal abstracts unless you add the [InternalsVisibleTo] directive.
[assembly: InternalsVisibleTo("DynamicMockAssembly")]

See Mocking Interfaces and Abstract classes
answered Jun 19, 2007 by scott (29,080 points)
+1 vote
Well, in case of SharePoint dll, I can't add the internalsvisible, since it is compiled already. Is there any way to workaround this?
answered Jun 19, 2007 by phazer (850 points)
0 votes
As the method is internal, there must be other types in the SharePoint dll that extend SPWorkflowAssociationCollection, you can mock these instead.
I will also check to see if there is another way to do this.
answered Jun 19, 2007 by scott (29,080 points)
+2 votes
Though I'm working with AAA, I'm encountering the same problem as the original poster: But for the life of me, I can't figure out a workaround. Has anyone managed to find a way to mock a SPWorkflowAssociationCollection or one of it's extending classes (SPListWorkflowAssociationCollection)???
answered Dec 15, 2008 by sean.mcdermid@colost (380 points)
+2 votes
You might want to check the duck-type swapping:
You'll need an actual instance of SPWorkflowAssociationCollection and create a similar class with the required functionality.
You can read about it at:
https://www.typemock.com/Docs/UserGuide/ ... peAAA.html
answered Dec 16, 2008 by dhelper (23,700 points)
+2 votes
That looks like it would work, except the part where I need an actual instance of a class that extends from SPWorkflowAssociationCollection (public abstract, with a protected constructor, and a number of protected abstract methods).

Since the out-of-the-box classes that extend from SPWorkflowAssociationCollection are all scoped as "protected", I can't think of a way to implement one of those (please tell me if I'm wrong!).

I thought I could swap instances of SPWorkflowAssociationCollection with a monstrosity of my own creation using Isolate.Swap.NextInstance<T>, but that fell short. Maybe obviously to some, I don't seem to be able to implement protected abstract methods (again, I worry my own coding ignorance shows through here).

My final thought on how to implement your suggestion is to instantiate a reference to an actual SharePoint site and retrieve a "live" instance of a SPWorkflowAssociationCollection; however, that kind of defeats the purpose of Test Driven Development doesn't it? The tests then MUST be run on a machine with SharePoint installed.

I understand that sometimes you have to do what you have to do, but I had hopes that SharePoint would allow for an elegant solution in one way shape or form. High hopes seemingly dashed on the harsh rocks of coding reality.
answered Dec 16, 2008 by sean.mcdermid@colost (380 points)
+2 votes
Hi Sean,

I would really like to help you solve this issue.
Before throwing TDD away I would suggest we work together to find a way to work around this limitation, can you provide a code snippet (or your whole test) of what you are trying to accomplish so I can suggest how you can still test the desired feature without faking SPWorkflowAssociationCollection
answered Dec 17, 2008 by dhelper (23,700 points)
+2 votes
After digging a bit I found a solution for Mocking/Faking SPWorkflowAssociationCollection:

We can use the old API (reflective & natural) to mock one of the private classes that inherit from SPWorkflowAssociationCollection.


var assembly = typeof(SPWorkflowAssociationCollection).Assembly;
Type t = assembly.GetType("Microsoft.SharePoint.Workflow.SPListWorkflowAssociationCollection");

var mockSPList = MockManager.MockObject(typeof(SPList));
var mock = MockManager.MockObject(t, mockSPList.MockedInstance);

var fakeInstance = mock.MockedInstance as SPWorkflowAssociationCollection;

Assert.IsNotNull(fakeInstance);

The bad news is that faking private/internal is currently not (yet) implemented in AAA and you'll have to use older API in your test.
answered Dec 17, 2008 by dhelper (23,700 points)
+2 votes
Thanks for taking the time on this.

I did do a workaround that was not the least bit elegant: I wrapped the SPList.WorkflowAssociations.GetAssociationByName() call in it's own method and simply mocked the wrapping method. Not in the least bit pretty, but it worked. I'll definitely give your suggestion a try.

Here's the code for the hack (which is just the offending call moved to it's own method):


private static SPWorkflowAssociation GetWorkflowAssociation(string associatedWorkflowName, SPList list)
      {
         return list.WorkflowAssociations.GetAssociationByName(associatedWorkflowName, CultureInfo.CurrentCulture);
      }


Here is the code for the test, with my original efforts commented out:

//Isolate.WhenCalled(() => fakeTargetList.WorkflowAssociations.GetAssociationByName(associatedWorkflowName, CultureInfo.CurrentCulture)).WillReturn(fakeWorkflowAssociation);
         
Isolate.NonPublic.WhenCalled(typeof(ListToolKit), "GetWorkflowAssociation").WillReturn(fakeWorkflowAssociation);
answered Dec 17, 2008 by sean.mcdermid@colost (380 points)
...