Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make method only callable from unit test

Is it possible to write methods, which are only callable by unit tests? My problem is that our framework contains a lot of Singleton classes, which makes unit testing quite hard some time. My idea was to create a simple interface like this:

public interface IUnitTestClearable
{
    void ClearForUnitTest();
}

This method will be called for "resetting" singleton instances for better handling of unit tests. But this method should only be callable from unit test classes/instances. Is this possible?

like image 428
BendEg Avatar asked Nov 20 '15 12:11

BendEg


People also ask

Should I make method public for testing?

A unit test should test the public contract, the only way how a class could be used in other parts of the code. A private method is implementation details, you should not test it; as far as public API works correctly, the implementation doesn't matter and could be changed without changes in test cases.

Is it good practice to make all methods public?

Yes it is very bad practice - you're letting your tools make design decisions for you. I think the main problem here is that you're trying to treat each individual method as a unit. This is generally the cause of all unit test woes.

Can you mock a private method MOQ?

Moq supports mocking protected methods. Changing the methods to protected , instead of private , would allow you to mock their implementation.

Can we write unit test for private methods?

Unit Tests Should Only Test Public Methods The short answer is that you shouldn't test private methods directly, but only their effects on the public methods that call them. Unit tests are clients of the object under test, much like the other classes in the code that are dependent on the object.


3 Answers

You can make a method internal and then set InternalsVisibleTo. This way, you give another assembly access to your internals

http://geekswithblogs.net/jwhitehorn/archive/2007/11/09/116750.aspx

but Tim was just before me as I end this :)

In your project file, AssemblyInfo.cs, set

[assembly: InternalsVisibleTo("Application.Test")]

or if you have a signed assembly

[assembly: InternalsVisibleTo("Application.Test, PublicKey=KEYHERE")]
like image 101
lordkain Avatar answered Oct 03 '22 21:10

lordkain


Providing access to unit tests while controlling or preventing other things (ab)using that access is a good idea. There are a number of ways this can be done but the simplest is to use InternalsVisibleTo

https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.internalsvisibletoattribute

like image 30
Tim B Avatar answered Oct 03 '22 21:10

Tim B


You may not want to expose all private methods to your unit tests, as it might cause confusion, so just add a private method for your singleton classes.

public class MySingleton
{
    private void ClearForUnitTest()
    {
        Console.WriteLine("Cleared.");
    }
}

Create extension to be used in your unit tests.

public static class PrivateExtensions
{
    public static void ClearForUnitTest<T>(this T instance)
    {
        var method = typeof(T).GetMethod("ClearForUnitTest", BindingFlags.NonPublic | BindingFlags.Instance);
        method.Invoke(instance, null);
    }
}

Use like it would be public

private static void Main(string[] args)
{
    var ms = new MySingleton();
    ms.ClearForUnitTest();
}

profit

like image 23
Janne Matikainen Avatar answered Oct 03 '22 22:10

Janne Matikainen