Question

I have a class holding complex scientific computations. It is set up to only allow a user to create a properly instantiated case. To properly test the code, however, requires setting internal state variables directly, since the reference documents supply this data in their test cases. Done improperly, however, it can invalidate the state.

So I must have the ability, a member function, to set internal variables from the unit test programs. But I want to strongly discourage normal users from calling this function. (Yes, a determined user can muck with anything... but I don't want to advertise that there is a way to do something wrong.)

It would be nice to be able to tell Intellisense to not show the function, for instance.

The best solution I have at the moment is to just name the function something like: DangerousSet().

What other options do I have?

Follow-Up

I found David B's answer most useful to my situation. Thanks!
Mufasa's suggestion to use reflection was great, but harder to implement (for me).
Chris' suggestion of using a decorator was good, but didn't pan out.
BFree's suggestion on XML is also good, and was already in use, but doesn't really solve the problem.

Finally, BillTheLizard's suggestion that the problem is in the source documents is not something I can control. International experts publish highly technical books and journal articles for use by their community. The fact that they don't address my particular needs is a fact of life. There simply are no alternative documents.

Was it helpful?

Solution

Suppose you want to test this object by manipulating its fields.

public class ComplexCalculation
{
    protected int favoriteNumber;
    public int FavoriteNumber
    {
        get { return favoriteNumber; }
    }
}

Place this object in your test assembly/namespace:

public class ComplexCalculationTest : ComplexCalculation
{
    public void SetFavoriteNumber(int newFavoriteNumber)
    {
        this.favoriteNumber = newFavoriteNumber;
    }
}

And write your test:

    public void Test()
    {
        ComplexCalculationTest myTestObject = new ComplexCalculationTest();
        myTestObject.SetFavoriteNumber(3);
        ComplexCalculation myObject = myTestObject;

        if (myObject.FavoriteNumber == 3)
            Console.WriteLine("Win!");

    }

PS: I know you said internal, but I don't think you meant internal.

OTHER TIPS

You can use InternalsVisibleToAttribute to mark internal members as visible to your test assembly. It seems to shine when used in this context, though its not quite "friend".

  1. Mark your DangerousSet function internal instead of public.

  2. In Properties\AssemblyInfo.cs of the project containing DangerousSet:

    [assembly:InternalsVisibleTo("YourTestAssembly")]

If you have two test assemblies for whatever reason, the syntax is:

[assembly:InternalsVisibleTo("TestAssembly1"), 
    InternalsVisibleTo("TestAssembly2")]

Decorate your method with this attribute:

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]

This will hide it from Intellisense.

EDIT:

But apparently this has a rather significant caveat: "In Visual C#, EditorBrowsableAttribute does not suppress members from a class in the same assembly." Via MSDN.

It sounds like your real problem is in your reference documents. You shouldn't test cases that are impossible to encounter under proper use of your class. If users shouldn't be allowed to change the state of those variables, then neither should your tests.

You can also use reflection. Google search turned up Unit testing private methods using reflection.

Can your test code include a subclass of the calculations class? If so, you can mark the function protected and only inheritors will be able to use it. I'm pretty sure this also takes it out of intellisense, but I could be wrong about that.

What I've done in the past is I put XML Comments by the method and used the section to write in big bold letters. DON'T USE THIS METHOD or whatever. That way, if someone tried to use it, Intellisense would give them a nice warning.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top