views:

391

answers:

5

I have an issue with a class that I'm trying to test. I've declared a private enum and I'm using that in a generic dictionary in the code. This enum has no meaning outside of this class but it's used in a private method. When I generated the code the accessor is written into the generic dictionary type, but throws an invalid cast exception when I try to use the test.

MyClass_Accessor target = new MyClass_Accessor();
Dictionary<MyClass_Accessor.MyEnum, long> dictionary = new Dictionary<MyClass_Accessor.MyEnum, long>();
dictionary.Add(MyClass_Accessor.Myenum.EnumValue, 1);
target.Method(dictionary); //Throws invalid cast exception here.

The exception is that the generic dictionary of accessor => enum, long cannot be converted to Myclass => enum, long.

Other than altering my working class, is there a way that I can test this method?

A: 

Is there a public method that calls this private method and cause the exception to throw? can't you test that?

Ali Shafai
yes, but that would be an integration test. I'm trying to test the behaviour of that specific function so that I can trust it from the higher level functions.
Spence
It's not an integration tests. You're testing specific functionality of a class not it's dependency.
Vadim
A: 

I have to admit that the question is not clear to me. But it looks like you need to test your private method through a public caller.

In most cases when you TDD, you create a public method to satisfy your test and then refactor it in private tests if you need.

Vadim
No TDD for me :'(. I've been asked to add tests to an existing code base...It's all learning curve from here. So basically there is no way to leave a working test in place for this function, if you refactor the call away, then you lose the test as well if it needs to be changed...
Spence
A: 

I'll admit that I haven't called private functions that also have private definitions in the way that you have, but looking at your code you don't appear to have selected a valid value from your dictionary object.

Shouldn't the code be something like?

target.Method(dictionary[0]);

Okay, after your comment below.

The following code is taken from a test using private methods of a class (PaDeviceManager), could it be adapted to your requirements?

PaDeviceManager paDeviceManager = PaDeviceManager.Create;
PrivateObject param0 = new PrivateObject(paDeviceManager);
PaDeviceManager_Accessor target = new PaDeviceManager_Accessor(param0);
PaDeviceManager_Accessor();
ChrisBD
The method takes a dictionary of values, think of it as a shared state. I expect it to transform the values in the dictionary.
Spence
+4  A: 

You can use the InternalsVisibleTo assembly attribute, and change your privates to internals. (If you can't change your private enum to an internal enum, then this won't work, but usually its an acceptable trade off.)

Assuming you have an assembly called AssemblyA that is being unit tested by AssemblyATest, and integration tested by AssemblyAIntegTest, you can stick the following in your AssemblyInfo.cs file:

using System.Runtime.CompilerServices;

// ...

[assembly: InternalsVisibleTo("AssemblyATest")]
[assembly: InternalsVisibleTo("AssemblyAIntegTest")]

If you sign your primary assemblies, you will also need to sign your test assemblies, and provide fully qualified, cultured, and primary keyed assembly names.

jrista
I'm assuming that this will work because now instead of the dictionary being of the type specified, it's of the actual type. I'm letting this go down to 0 days, but this will probably work without changing the purpose of the class, but it would be good if I find a way to do this that is supported.
Spence
Microsoft added the InternalsVisibleTo attribute to support unit testing. It was one of the primary goals, and is used for that very purpose in Microsofts own libraries (a prominent example is the Enterprise Library 3.0 and 4.0, if you need an example of how its used.)
jrista
A: 

I'll readily admit that under your circumstances this is a test that you may need to perform, in which case jrista's answer is the one to follow (InternalsVisibleTo).

When unit-testing however I don't think you are normally supposed to test the non-public API of classes. If this enum is private to the class, and therefore only used internally to the class, then it should not occur in any unit tests either.

The purpose of unit tests it to establish that the public (including virtual/abstract protected) API of your class performs as expected. By including tests that rely on an implementation detail such as this private enum, you essentially make it impossible to change the implementation in the future (for example into one that may not need an enum).

jerryjvl