views:

125

answers:

2

I have two classes like this (in the actual project):

namespace app {
    internal class A {
    }

    internal class B {
        private List<A> list;
        private void SomeMethodToTest() {
            list = new List<A>() { new A() };
        }
    }

The I have my Unit test looking something like

[TestClass()]
public class ATest {
    [TestMethod()]
    public void TestSomeMethod() {
        B_Accessor b = new B_Accessor();
        b.SomeMethodToTest();
        Assert.AreEqual(1, b.list.Count); // ERROR ON THIS LINE
    }
}

On the marked line I get an InvalidCastException saying something like "unable to cast object of type System.Collections.Generic.List'1[app.A] to type System.Collections.Generic.List'1[app.A_Accessor]

The problem is that, because A is internal, the auto-generated class B_Accessor looks like

[Shadowing("app.B")]
public class B_Accessor : BaseShadow {
    ... stuff ...

    [Shadowing("list")]
    public List<A_Accessor> list { get; set; }

    ... stuff ...
}

Note that, in the Accessor class, the list is of type List<A_Accessor> and not List<A>. I have specified the InternalsVisibleTo attribute on the application, so the test project can access the type A, but for some reason VS replaces it with the accessor type, which makes the type incompatible with the wrapped type.

How can I work around this other than making A public?

A: 

I've deleted my previous answer because I hadn't noticed that you were already using InternalsVisibleToAttribute.

What's generating these "accessor" classes? When you say "VS replaces it with the accessor type" do you mean it changes your source code? That sounds very odd - what happens if you put it back to just use A and B instead of A_Accessor and B_Accessor?

If you can possibly get rid of autogenerated classes which are meant to look like the real ones, but don't quite, then do get rid of them. I suspect this is just one situation where they'll cause problems.

I've never had any problems just using InternalsVisibleTo and testing internal members directly. (Well, R# sometimes got confused in a previous version, but apart from that...)

Jon Skeet
VS generates the accessor classes automagically when the test project is built. I can't use B instead of B_Accessor since I want to access a private member.
erikkallen
OK, so how do you test a private method? I'd prefer not to break encapsulation for the testing to work.
erikkallen
http://stackoverflow.com/questions/250692/how-do-you-unit-test-private-methods
JeffH
Ick - I'd steer clear of autogenerated accessor code, personally. I usually try to avoid directly testing methods which want to be private, but if I *have* to I usually go with making them internal. It's not ideal, but it's pragmatic.
Jon Skeet
I guess it's a matter of style whether to test private methods. I have a bunch of methods which populate the internal state of classes, and the only reasonable way to determine whether they populate the state correctly is to inspect private members.
erikkallen
... since I prefer not to have an ocean of classes which are only used for one specific purpose.
erikkallen
Well, you've got to consider the cost of using these accessor classes vs the encapsulation hit of making the private methods internal.
Jon Skeet
A: 

It is possible to replace the test project with something like

internal static class AccessorExtensionMethods {
    internal static List<A> Get_list(this PrivateObject po) {
        return (List<A>)po.GetField("list");
    }
}

[TestClass()]
public class ATest {
    [TestMethod()]
    public void TestSomeMethod() {
        PrivateObject bpo = new PrivateObject(new B());
        B_Accessor b = new B_Accessor(bpo);
        b.SomeMethodToTest();
        Assert.AreEqual(1, bpo.Get_list().Count);
    }
}
erikkallen