411

Visual Studio allows unit testing of private methods via an automatically generated accessor class. I have written a test of a private method that compiles successfully, but it fails at runtime. A fairly minimal version of the code and the test is:

//in project MyProj
class TypeA
{
    private List<TypeB> myList = new List<TypeB>();

    private class TypeB
    {
        public TypeB()
        {
        }
    }

    public TypeA()
    {
    }

    private void MyFunc()
    {
        //processing of myList that changes state of instance
    }
}    

//in project TestMyProj           
public void MyFuncTest()
{
    TypeA_Accessor target = new TypeA_Accessor();
    //following line is the one that throws exception
    target.myList.Add(new TypeA_Accessor.TypeB());
    target.MyFunc();

    //check changed state of target
}

The runtime error is:

Object of type System.Collections.Generic.List`1[MyProj.TypeA.TypeA_Accessor+TypeB]' cannot be converted to type 'System.Collections.Generic.List`1[MyProj.TypeA.TypeA+TypeB]'.

According to intellisense - and hence I guess the compiler - target is of type TypeA_Accessor. But at runtime it is of type TypeA, and hence the list add fails.

Is there any way I can stop this error? Or, perhaps more likely, what other advice do other people have (I predict maybe "don't test private methods" and "don't have unit tests manipulate the state of objects").

Sibeesh Venu
  • 18,755
  • 12
  • 103
  • 140
junichiro
  • 5,282
  • 3
  • 18
  • 26
  • You need an accessor for private class TypeB. Accessor TypeA_Accessor provides access to private and protected methods of TypeA. However TypeB is not a method. It is a class. – Dima Apr 08 '13 at 22:13
  • Accessor provides access to private/protected methods, members, properties, and events. It does not provide access to private/protected classes within your class. And private/protected classes (TypeB) are intended to be used only by methods of owning class (TypeA). So basically you are trying to add private class (TypeB) from outside of TypeA to "myList" which is private. Since you are using accessor, there is no problem to access myList. However you can not use TypeB through accessor. Posiible solution would be to move TypeB outside of TypeA. But it can break your design. – Dima Apr 08 '13 at 22:23
  • 1
    Feel that testing private methods should be done by the following https://stackoverflow.com/questions/250692/how-do-you-unit-test-private-methods – nate_weldon Aug 30 '17 at 17:26

18 Answers18

818

If using a version prior to .NET Core 2.0, you can use the PrivateObject class:

Class target = new Class();
PrivateObject obj = new PrivateObject(target);
var retVal = obj.Invoke("PrivateMethod");
Assert.AreEqual(expectedVal, retVal);

PrivateObject and PrivateType support was removed in .NET Core 2.0.

Andrew D. Bond
  • 902
  • 1
  • 11
  • 11
Scuttle
  • 8,277
  • 2
  • 13
  • 9
  • 33
    This is the correct answer, now that Microsoft has added PrivateObject. – Zoey Jan 27 '14 at 11:57
  • 4
    Good answer but please note that the PrivateMethod needs to be "protected" in stead of "private". – HerbalMart Mar 13 '14 at 11:54
  • How about invoking a method in an abstract class? (a class that can not be constructed on its own...). Instantiate a derived class? Hmmm not so nice. Some other reflection tricks? Anyone... ? – Mike de Klerk Apr 18 '14 at 19:20
  • 26
    @HerbalMart: Perhaps I misunderstand you, but if you are suggesting that PrivateObject can only access protected members and not private ones, you are mistaken. – kmote Jun 18 '14 at 18:37
  • @MikedeKlerk I think PrivateType class will help. For more details see http://stackoverflow.com/questions/4883944/privateobject-does-not-find-property – Jason Parker Jul 10 '14 at 15:07
  • and what about when the private method is void? – Rafal_Koscinski Jul 22 '14 at 09:02
  • 1
    @Rafal_Koscinski then what do you expect it to do? If it's void, it can run successfully or throw an exception. You can assert for exceptions when calling obj.Invoke("PrivateMethod") – Rast Dec 11 '14 at 16:58
  • @HerbalMart - it seems PrivateObject can be used with private methods now (not just protected). I just used it with a private method and it worked fine. Its a very useful feature! – namford Aug 05 '15 at 09:15
  • 1
    Would the suggestion work for a static class? If so, can you provide an example? – Jeff Pearce Feb 25 '16 at 21:12
  • 1
    How to resolve the problem with the refactoring of method name? – Dawid Wekwejt Mar 15 '17 at 08:05
  • 24
    @JeffPearce For static methods you can use "PrivateType pt = new PrivateType(typeof(MyClass));", and then call InvokeStatic on the pt object as you would call Invoke on a private object. – Steve Hibbert May 02 '17 at 09:45
  • Very useful this. Had this up and running in 5 minutes and gives me the confidence that stuff I feel rightly should be private, can also be unit tested. – Mike Upjohn Nov 02 '17 at 13:41
  • 14
    In case anyone was wondering as of MSTest.TestFramework v1.2.1 - the PrivateObject and PrivateType classes are unavailable for projects targeting .NET Core 2.0 - There's a github issue for this: https://github.com/Microsoft/testfx/issues/366 – shiitake Apr 12 '18 at 20:06
  • PrivateObject for `call method with parameters` ? – Kiquenet Jun 13 '18 at 13:32
  • 1
    PrivateObject for call ***static*** `method with parameters` ? – Kiquenet Jun 13 '18 at 13:32
  • 3
    @Kiquenet obj.Invoke("TestMethod", toPassIn); The method takes an array of objects as params – Lord Darth Vader Jun 27 '18 at 07:04
  • obj.Invoke("PrivateMethod") allows for a second parameter, an object array which represents your method parameters, e.g. obj.Invoke("PrivateMethod", myparams) where myparams is object[] – robnick Jan 10 '19 at 23:47
  • 1
    missing in ".NET Core 3+" as well, had to copy the source code files from Microsoft GitHub directly into my project – Aaron. S Jan 04 '20 at 23:09
  • 1
    to make the "code-smell" go away and to make the life of the testers easier, you can write `nameof(MyMethod)` instead of "MyMethod" – Bizhan Feb 05 '20 at 20:39
  • 1
    @Bizhan if `MyMethod` is private or protected, and it's inside another class, you won't be able to do this. – c-chavez Mar 11 '20 at 13:29
  • @c-chavez of course the code doesn't run on its own. You need to have an extra public constant. Generally it's a bad idea to write down the method/class names within double quotations. – Bizhan Mar 11 '20 at 15:03
  • 1
    @Bizhan I think this is also useful, but in some cases it could create a lot of new constants. I also agree there should be some sort of getting this property without a string, since if this name is changed, you won't see an error until you compile and run the tests. – c-chavez Mar 11 '20 at 15:16
  • @c-chavez that's a good argument, I didn't think of it in this context. *if the name changes the test simply fails.* – Bizhan Mar 11 '20 at 15:22
  • 1
    For `Assert.ThrowsException()` to work, you must catch `TargetInvocationException` from `Invoke()` or `InvokeStatic()`, and re-throw `InnerException`. – Christian Davén Jun 03 '20 at 06:37
  • What about private classes? – Aaron Franke Aug 24 '21 at 14:02
  • This is perfect and exactly what I was looking for. One note, if the method has parameters you need to pass them separately or it can not find the quoted method name. Look at Jack Davidsons post a few down from this one for syntax. – MDGREEE Feb 24 '22 at 13:47
117

“There is nothing called as standard or best practice, probably they are just popular opinions”.

Same holds true for this discussion as well.

enter image description here

It all depends on what you think is a unit , if you think UNIT is a class then you will only hit the public method. If you think UNIT is lines of code hitting private methods will not make you feel guilty.

If you want to invoke private methods you can use "PrivateObject" class and call the invoke method. You can watch this indepth youtube video ( http://www.youtube.com/watch?v=Vq6Gcs9LrPQ ) which shows how to use "PrivateObject" and also discusses if testing of private methods are logical or not.

Community
  • 1
  • 1
Shivprasad Koirala
  • 27,644
  • 7
  • 84
  • 73
  • 12
    All the pedantic wankery in our field causes more problems than it solves. This is why one of my programming teachers said, "Make everything public!" – codewise Dec 10 '20 at 20:58
  • 5
    What codewise said. "pedantic wankery" - sums it up perfectly. – Richard Moore Sep 28 '22 at 16:00
  • 1
    Another approach is noting that this is a dilemma caused by the interaction of different paradigms, goals and implementations. Then, based on needs, making a choice. For example, perhaps its preferred to keep tests in a separate project, compiling separate assemblies, but still tests methods that are for all intents and purposes confined to the tested assembly, declaring those `public`. I'd argue such architectural decisions benefit from deliberation. But then again I do enjoy myself some pedantic wankery – CervEd Nov 14 '22 at 17:00
104

Another thought here is to extend testing to "internal" classes/methods, giving more of a white-box sense of this testing. You can use InternalsVisibleTo attribute on the assembly to expose these to separate unit testing modules.

In combination with sealed class you can approach such encapsulation that test method are visible only from unittest assembly your methods. Consider that protected method in sealed class is de facto private.

[assembly: InternalsVisibleTo("MyCode.UnitTests")]
namespace MyCode.MyWatch
{
    #pragma warning disable CS0628 //invalid because of InternalsVisibleTo
    public sealed class MyWatch
    {
        Func<DateTime> _getNow = delegate () { return DateTime.Now; };
    

       //construktor for testing purposes where you "can change DateTime.Now"
       internal protected MyWatch(Func<DateTime> getNow)
       {
           _getNow = getNow;
       }

       public MyWatch()
       {            
       }
   }
}

And unit test:

namespace MyCode.UnitTests
{

[TestMethod]
public void TestminuteChanged()
{
    //watch for traviling in time
    DateTime baseTime = DateTime.Now;
    DateTime nowforTesting = baseTime;
    Func<DateTime> _getNowForTesting = delegate () { return nowforTesting; };

    MyWatch myWatch= new MyWatch(_getNowForTesting );
    nowforTesting = baseTime.AddMinute(1); //skip minute
    //TODO check myWatch
}

[TestMethod]
public void TestStabilityOnFebruary29()
{
    Func<DateTime> _getNowForTesting = delegate () { return new DateTime(2024, 2, 29); };
    MyWatch myWatch= new MyWatch(_getNowForTesting );
    //component does not crash in overlap year
}
}
Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
Jeff
  • 1,577
  • 1
  • 11
  • 8
  • I'm not sure I understand. InternalsVisibleToAttribute makes methods and attributes which are marked as "internal" accessible, but my fields and methods are "private". Are you suggesting I change things from being private to internal? I think I misunderstand. – junichiro Feb 03 '12 at 02:36
  • 3
    Yes, that's what I'm suggesting. It's a little bit "hacky", but at least they're not "public". – Jeff Mar 15 '12 at 01:04
  • 46
    This is a wonderful answer **just** because it doesn't say "don't test private methods" but yes, it's quite "hacky". I wish there was a solution. IMO it's bad to say "private methods shouldn't be tested" because the way **I** see it: it's equivalent to "private methods shouldn't be correct". – MasterMastic Jun 06 '13 at 17:25
  • 5
    ya ken, I also confused by those who claim that private methods shouldn't be tested in unit test. Public API are the output, but sometimes wrong implementation also give the right output. Or the implementation made some bad side effects, e.g. holding resources that are not necessary, referencing objects preventing it from being collected by gc...etc. Unless they provide other test that can cover the private methods rather than unit test, otherwise I would consider that they can't maintain a 100% tested code. – mr.Pony Jun 10 '13 at 09:59
  • I agree with MasterMastic. This should be the accepted answer. – XDS Nov 06 '18 at 12:21
  • 3
    Nice. I was not aware of this. Exactly what I needed. Let's say I build a 3rd party component for others to use, but I only want to expose a very limited API. Internally it's quite complex and I would like to test individual components (like an input parser or validator for example), but i don't want to make those public. The end-user shouldn't need to know anything about those. I know the standard approach here is "test only your public API", but I would prefer testing single responsibility units of code instead. This allows me to do it without making them public. – kowgli Feb 25 '19 at 19:12
  • 3
    I think it should be the accepted answer too. Debate about private method testing is cool to read, but it's more a matter of opinion. As I see it pretty good arguments have been made on both sides. If you still want/need to test private methods, you should have a way to. This is the only one that was provided. Additionally, you can do it for a whole assembly, using : [assembly: InternalsVisibleTo("UT.cs")] in your AssemblyInfo.cs – mgueydan Sep 02 '19 at 12:07
  • 1
    I used this method but my assemblies were strongly named. So I had to make my unit test dll also strongly named and added this to my assembly. [assembly:InternalsVisibleTo("Name of your unit test assembly here,PublicKey=e05516a3****")] – kuradac Sep 10 '19 at 15:22
  • Found this article talking about this concept too. I think it could be useful. https://improveandrepeat.com/2019/12/how-to-test-your-internal-classes-in-c/ – Darkgaze Nov 27 '20 at 09:23
48

One way to test private methods is through reflection. This applies to NUnit and XUnit, too:

MyObject objUnderTest = new MyObject();
MethodInfo methodInfo = typeof(MyObject).GetMethod("SomePrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance);
object[] parameters = {"parameters here"};
methodInfo.Invoke(objUnderTest, parameters);
Jack Davidson
  • 4,613
  • 2
  • 27
  • 31
  • `call methods` ***static*** and ***non static*** ? – Kiquenet Jun 13 '18 at 13:35
  • 2
    The downside of reflection-reliant methods is that they tend to break when you rename methods using R#. It might not be a big problem on small projects but on huge code-bases it becomes kinda nagging to have unit tests breaking in such a fashion and then having to go around and quick-fix them. In this sense I my money goes to Jeff's answer. – XDS Nov 06 '18 at 12:23
  • 5
    @XDS Too bad nameof() doesn't work to get the name of a private method from outside its class. – Gabriel Morin Feb 06 '19 at 20:29
26

Ermh... Came along here with exactly the same problem: Test a simple, but pivotal private method. After reading this thread, it appears to be like "I want to drill this simple hole in this simple piece of metal, and I want to make sure the quality meets the specs", and then comes "Okay, this is not to easy. First of all, there is no proper tool to do so, but you could build a gravitational-wave observatory in your garden. Read my article at http://foobar.brigther-than-einstein.org/ First, of course, you have to attend some advanced quantum physics courses, then you need tons of ultra-cool nitrogenium, and then, of course, my book available at Amazon"...

In other words...

No, first things first.

Each and every method, may it private, internal, protected, public has to be testable. There has to be a way to implement such tests without such ado as was presented here.

Why? Exactly because of the architectural mentions done so far by some contributors. Perhaps a simple reiteration of software principles may clear up some missunderstandings.

In this case, the usual suspects are: OCP, SRP, and, as always, KIS.

But wait a minute. The idea of making everything publicly available is more of less political and a kind of an attitude. But. When it comes to code, even in then Open Source Community, this is no dogma. Instead, "hiding" something is good practice to make it easier to come familiar with a certain API. You would hide, for example, the very core calculations of your new-to-market digital thermometer building block--not to hide the maths behind the real measured curve to curious code readers, but to prevent your code from becoming dependent on some, perhaps suddenly important users who could not resist using your formerly private, internal, protected code to implement their own ideas.

What am I talking about?

private double TranslateMeasurementIntoLinear(double actualMeasurement);

It's easy to proclaim the Age of Aquarius or what is is been called nowadays, but if my piece of sensor gets from 1.0 to 2.0, the implementation of Translate... might change from a simple linear equation that is easily understandable and "re-usable" for everybody, to a pretty sophisticated calculation that uses analysis or whatever, and so I would break other's code. Why? Because they didn't understand the very priciples of software coding, not even KIS.

To make this fairy tale short: We need a simple way to test private methods--without ado.

First: Happy new year everyone!

Second: Rehearse your architect lessons.

Third: The "public" modifier is religion, not a solution.

CP70
  • 327
  • 3
  • 3
  • I agree completely. I'm also wondering what we should do, in case of selling a product that contains code. We have to be clear about the public API but it is great to have a bunch of tests for the internal functionality too. If everything is tested, and small, it will probably work correctly. But those little functions that nobody has to call, need to be tested too! – Darkgaze Nov 27 '20 at 09:18
  • 1
    Pick your poison. Code with strict access right, but thin unit tests, or copious unit tests on a class with completely public methods. Not exactly a choice a professional wants to make. – Mike Wise Jul 30 '21 at 09:43
14

Another option that has not been mentioned is just creating the unit test class as a child of the object that you are testing. NUnit Example:

[TestFixture]
public class UnitTests : ObjectWithPrivateMethods
{
    [Test]
    public void TestSomeProtectedMethod()
    {
        Assert.IsTrue(this.SomeProtectedMethod() == true, "Failed test, result false");
    }
}

This would allow easy testing of private and protected (but not inherited private) methods, and it would allow you to keep all your tests separate from the real code so you aren't deploying test assemblies to production. Switching your private methods to protected methods would be acceptable in a lot of inherited objects, and it is a pretty simple change to make.

HOWEVER...

While this is an interesting approach to solving the problem of how to test hidden methods, I am unsure that I would advocate that this is the correct solution to the problem in all cases. It seems a little odd to be internally testing an object, and I suspect there might be some scenarios that this approach will blow up on you. (Immutable objects for example, might make some tests really hard).

While I mention this approach, I would suggest that this is more of a brainstormed suggestion than a legitimate solution. Take it with a grain of salt.

EDIT: I find it truly hilarious that people are voting this answer down, since I explicitly describe this as a bad idea. Does that mean that people are agreeing with me? I am so confused.....

Many Years Later Edit: I was looking over some old responses and I came across this one. My original intent was to playfully suggest what I thought was a silly idea, just to give the question author some crazy brainstormed options.

I thought the response was silly because it breaks the whole idea of using private methods, and exposes everything as public by doing an end run around the security model.

If I were to respond to this question today, I wouldn't beat around the bush quite so much, simply advocate making the methods public. I will go out on a limb and say that probably 99% of all the private methods EVER WRITTEN don't need to be private, and the whole practice of encapsulation hiding is a complete waste of time. (Boom!)

There are always going to be a few exceptions where their use is legitimately needed, but I am of the firm opinion that if you cannot test your code, you are probably writing bad code.

Good engineers test all their work, period. - Me

The default state of all methods should be public, and only changed when this will cause functionality to outright fail. You should not have to work around encapsulation in order to be able to make your code bullet proof.

So, go open up your code and get it tested!

Roger Hill
  • 3,677
  • 1
  • 34
  • 38
8

From the book Working Effectively with Legacy Code:

"If we need to test a private method, we should make it public. If making it public bothers us, in most cases, it means that our class is doing too much and we ought to fix it."

The way to fix it, according to the author, is by creating a new class and adding the method as public.

The author explains further:

"Good design is testable, and design that isn't testable is bad."

So, within these limits, your only real option is to make the method public, either in the current or a new class.

Kai Hartmann
  • 3,106
  • 1
  • 31
  • 45
  • 5
    Secure coding practices dictate that we should make everything private unless it absolutely needs to be public, like an API interface. If every little thing in your program is somewhere defined as public then it could be called by malicious actors to use your code to attack the system. You want to reduce the attack surface of your binaries while also being testable. – HackSlash Aug 21 '20 at 21:37
  • 3
    @hackslash making things private doesn't hide anything and doesn't prohibit other assemblies or objects from actually calling them. It just adds compile time type checking. – CervEd Dec 15 '20 at 23:15
  • 4
    This is sound advice to consider when faced with this problem, but definitely not the go-to answer. Essentially it says "never use private methods" (or alternatively: don't test all your methods). In fairy tale academia or in-house app development scenarios that might work. But forget it for a complex library with a public API. Imagine you already have a complex library with a large object graph of inter-dependent classes. Now make it WAY more difficult by moving all private code to new dummy classes and somehow share state with them. – enzi Apr 20 '21 at 12:55
  • 3
    Instead of answering the original question ("how do I test private methods?"), this resposnse instead answers the question that no one has asked ("should I test private methods?"). – bazzilic May 11 '21 at 08:14
  • Making method public just for a sake of unit test, Isn't it worth. If the method is used for a specific purpose and bind to a specific class then making it public and moving it to the separate class may expose it to the rest of the application. Following coding guideline until it suits better, just to follow it may lead to a serious problem, Exceptions are there!!! – Sumit Jambhale Mar 20 '23 at 05:59
5

It's 2022 now!

...and we have .NET6

While this does not really answer the question, my preferred approach these days is to collocate code and test in the same C# project, with naming convention like <ClassName>.Tests.cs. Then I use internal access modifier instead of private.

In the project file, I have something like this:

<ItemGroup Condition="'$(Configuration)' == 'Release'">
  <Compile Remove="**\*.Tests.cs" />
</ItemGroup>

to exclude the test files in release builds. Modify as needed.

FAQ 1: But sometimes you want to also test code in Release (optimized) build.

Answer: I find it unnecessary. I trust that the compiler will do its job without messing up my intent. So far, I've had no reason to question its ability to do so.

FAQ 2: But I really want to keep the method (or class) private.

Answer: Lots of excellent solutions in this page to try out. In my experience, having access modifier set to internal is usually more than enough since the method (or class) won't be visible outside the project it's defined. Beyond that, there's nothing more to hide.

Soma Mbadiwe
  • 1,594
  • 16
  • 15
  • Very interesting, but do they play nicely with unit test runners or IDEs? – nodakai Oct 11 '22 at 08:25
  • 1
    @nodakai yes they do. I code mostly with Visual Studio and occasionally VS Code. As long as the `Configuration` is not set to `Release`, the tests are available and run like you would expect. – Soma Mbadiwe Nov 03 '22 at 16:56
4

I use this helper (object type extension)

 public static  TReturn CallPrivateMethod<TReturn>(
        this object instance,
        string methodName,
        params object[] parameters)
    {
        Type type = instance.GetType();
        BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Instance;
        MethodInfo method = type.GetMethod(methodName, bindingAttr);

        return (TReturn)method.Invoke(instance, parameters);
    }

You can call it like this

Calculator systemUnderTest = new Calculator();
int result = systemUnderTest.CallPrivateMethod<int>("PrivateAdd",1,8);

One of the advantages is that it uses generics to pre-determine return type.

lstanczyk
  • 1,313
  • 13
  • 20
2

Extract private method to another class, test on that class; read more about SRP principle (Single Responsibility Principle)

It seem that you need extract to the private method to another class; in this should be public. Instead of trying to test on the private method, you should test public method of this another class.

We has the following scenario:

Class A
+ outputFile: Stream
- _someLogic(arg1, arg2) 

We need to test the logic of _someLogic; but it seem that Class A take more role than it need(violate the SRP principle); just refactor into two classes

Class A1
    + A1(logicHandler: A2) # take A2 for handle logic
    + outputFile: Stream
Class A2
    + someLogic(arg1, arg2) 

In this way someLogic could be test on A2; in A1 just create some fake A2 then inject to constructor to test that A2 is called to the function named someLogic.

Darkgaze
  • 2,280
  • 6
  • 36
  • 59
o0omycomputero0o
  • 3,316
  • 4
  • 31
  • 45
  • How would you test a scenario where the responsibility of the class is to produce data (which it does privately, say, by handling an event from some third party library) and then expose that data publicly in a known format, and you want to test that public interface? None of the answers here claiming we should not test methods account for producer scenarios. – allmhuran Oct 04 '21 at 12:06
  • @allmhuran: you should provide one more constructor which contains input event producer for example: p = ProduceData(inputEventProducer); then simulate event ocurring by calling inputEventProducer.emit("some event" ) and test the output of p. In general, if it is hard to test there are some problem with code that we need to refactor. Or if you cannot modified code you need some higher level testing like intergation or E2E. – o0omycomputero0o Oct 05 '21 at 00:51
  • But that constructor wouldn't be part of the normal flow of the production application. You'd basically be coding a mock into the non-mock class just for the sake of testing. This is why it makes sense to be able to call the private method as part of a test... because that's what's actually going to happen in production. That is to say, yes, the translator takes an injected dependency, but the injected dependency is from a third party library (it may be a class, not an interface). – allmhuran Oct 05 '21 at 03:47
1
public static class PrivateMethodTester
{
    public static object InvokePrivateMethodWithReturnType<T>(this T testObject, string methodName, Type[] methodParamTypes, object[] parameters)
    {
        //shows that we want the nonpublic, static, or instance methods.
        var flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance;

        //gets the method, but we need the methodparamtypes so that we don't accidentally get an ambiguous method with different params.
        MethodInfo methodInfo = testObject.GetType().GetMethod(methodName, flags, null, methodParamTypes, null);
        if (methodInfo == null)
        {
            throw new Exception("Unable to find method.");
        }

        //invokes our method on our object with the parameters.
        var result = methodInfo.Invoke(testObject, parameters);
        if (result is Task task)
        {
            //if it is a task, it won't resolve without forcing it to resolve, which means we won't get our exceptions.
            task.GetAwaiter().GetResult();
        }

        return result;
    }
}

Call it this way:

        Type[] paramTypes = new Type[] { typeof(OrderTender), typeof(string) };
        var parameters = new object[] { orderTender, OrderErrorReasonNames.FailedToCloneTransaction };

        myClass.InvokePrivateMethodWithReturnType("myPrivateMethodName", paramTypes, parameters);
Patrick Knott
  • 1,666
  • 15
  • 15
1

There's no ideal solution to this but one of the least-bad is to use Friend Assemblies.

It means marking your methods as internal in order to make them unit testable, which isn't ideal but it's better than making them public and therefore directly callable by everything. It's also very simple to do and the only impact is

Bugblatter
  • 11
  • 1
  • "and the only impact is".......... what! – Reece Aug 01 '23 at 17:48
  • 1
    The only impact is that your posts get truncated. I was probably going to say that you're not making methods and properties private that you normally would. – Bugblatter Aug 02 '23 at 18:50
0

In VS 2005/2008 you can use private accessor to test private member,but this way was disappear in later version of VS

Allen
  • 569
  • 9
  • 22
  • 2
    Good answer back in 2008 to perhaps early 2010. Now please refer to PrivateObject and Reflection alternatives (see several answers above). VS2010 had accessor bug(s), MS deprecated it in VS2012. Unless you are forced to stay in VS2010 or older (>18 years old build tooling) please save yourself time by avoiding private accessors. :-). – Zephan Schroeder Mar 01 '19 at 01:27
0

You can use nested classes to test private methods. For example (NUnit v3 is used):

    
    internal static class A
    {
        // ... other code

        private static Int32 Sum(Int32 a, Int32 b) => a + b;

        [TestFixture]
        private static class UnitTests
        {
            [Test]
            public static void OnePlusTwoEqualsThree()
            {
                Assert.AreEqual(3, Sum(1, 2));
            }
        }
    }

Furthermore tests related code can be moved to another file using 'partial class' feature, excluded from release builds using 'conditional compilation', etc. Advanced example:

File A.cs

    
    internal static partial class A
    {
        // ... other code

        private static Int32 Sum(Int32 a, Int32 b) => a + b;
    }

File A.UnitTests.cs


#if UNIT_TESTING
    partial class A
    {
        [TestFixture]
        private static class UnitTests
        {
            [Test]
            public static void OnePlusTwoEqualsThree()
            {
                Assert.AreEqual(3, Sum(1, 2));
            }
        }
    }
#endif

cyril.andreichuk
  • 343
  • 3
  • 11
0

I had another approach that it works for me. because I always run my tests in debug mode so I used #if DEBUG to add public before my private method. so my private method is like this:

public class Test
{
    #if (DEBUG)
      public
    #endif
    string PrivateMehtod()
    {
      return "PrivateMehtod called";
    }
}
Amirhossein Yari
  • 2,054
  • 3
  • 26
  • 38
  • Sometimes you _want to_ run your tests in release mode so that the _optimized_ code is also tested. – Coding Enthusiast Jan 21 '22 at 15:27
  • Yes, this code works for Debug mode, but you can add another mode that run in release and optimize mode and use it just for test. for example change it to `#if (DEBUG || OptimizeMode)` and test in debug mode, for sure test in `OptimizeMode` at the end – Amirhossein Yari Jan 25 '22 at 10:19
  • 1
    This could make sense with two new solution configurations, DEBUG_TEST and DEBUG_RELEASE. Otherwise, it will behave normally. – N-ate Apr 05 '22 at 17:29
0

Sadly there is no PrivateObject class in .net6

However I wrote a small extension method capable of invoking private methods using reflection.

Have a look at the sample code:

class Test
{
  private string GetStr(string x, int y) => $"Success! {x} {y}";
}

var test = new Test();
var res = test.Invoke<string>("GetStr", "testparam", 123);
Console.WriteLine(res); // "Success! testparam 123"

And here is the implementation of the extension method:

/// <summary>
/// Invokes a private/public method on an object. Useful for unit testing.
/// </summary>
/// <typeparam name="T">Specifies the method invocation result type.</typeparam>
/// <param name="obj">The object containing the method.</param>
/// <param name="methodName">Name of the method.</param>
/// <param name="parameters">Parameters to pass to the method.</param>
/// <returns>The result of the method invocation.</returns>
/// <exception cref="ArgumentException">When no such method exists on the object.</exception>
/// <exception cref="ArgumentException">When the method invocation resulted in an object of different type, as the type param T.</exception>
/// <example>
/// class Test
/// {
///   private string GetStr(string x, int y) => $"Success! {x} {y}";
/// }
///
/// var test = new Test();
/// var res = test.Invoke&lt;string&gt;("GetStr", "testparam", 123);
/// Console.WriteLine(res); // "Success! testparam 123"
/// </example>
public static T Invoke<T>(this object obj, string methodName, params object[] parameters)
{
  var method = obj.GetType().GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
  if (method == null)
  {
    throw new ArgumentException($"No private method \"{methodName}\" found in class \"{obj.GetType().Name}\"");
  }

  var res = method.Invoke(obj, parameters);
  if (res is T)
  {
    return (T)res;
  }

  throw new ArgumentException($"Bad type parameter. Type parameter is of type \"{typeof(T).Name}\", whereas method invocation result is of type \"{res.GetType().Name}\"");
}
0

If PrivateObject is not available and if the class under test is not a sealed class, you can make the methods and properties you want to expose protected. Create an inherited class in the unit test file with internal methods that expose the private methods/properties under test.

If the class under test is:

class MyClass{private string GetStr(string x, int y) => $"Success! {x} {y}";}

Change it to:

class MyClass{protected string GetStr(string x, int y) => $"Success! {x} {y}";}

In your unit test file create an inherited class something like this:

class MyClassExposed: MyClass 
{
    internal string ExposedGetStr(string x, int y)
    {
        return base.GetStr(x, y);
    }
}

Now you can use the inherited class MyClassExposed to test the exposed methods and properties.

WiiBopp
  • 2,750
  • 1
  • 14
  • 9
0

.NET doesn't allow use of Accessors anymore. You can use the code I posted here for an answer to a similar question.

How do you unit test private methods?

Dave Black
  • 7,305
  • 2
  • 52
  • 41