How to access private method? C #, VS 2012. Thank you. PS Former theme name - "Unit Test for private methods"
- one1. If the class is yours and you need access to the method outside, why do you declare it private? 2. If the class is not yours, access to the private method does not make sense, since it (a) is not designed for this, (b) with the next update may disappear --- You can use reflection as a temporary hack, just don't include this is in production code. - VladD
- Possible duplicate question: How to test private and protected methods? - Andrey NOP
3 answers
@Track (I’d definitely not fit in the comments :)
- How can we talk about
Unit
tests, but do not go about refactoring?
When a product is developed, the developer has only two possible options - either to write normal
production
code, or towrite-only
code that immediately goes to the garbage (Spike
in the terminology ofExtreme Programming
).In the first case,
Unit
tests specify the behavior of this code and are inextricably linked with refactoring, since they allow reducing the number of errors during its execution.In the second case,
Unit
tests are not needed by definition.
- If we talk about the topic of the question, then testing
private
methods is meaningless for several reasons:
The hypothetical green
Unit
test for the private method does not give any knowledge about the behavior of the corresponding class. Thisprivate
method may not be called at all from thepublic
methods of the class, and you will add an unnecessary test, which must also be supported.Contracts of
private
methods are extremely volatile. Today, let's say, the method is calledSafelyCreateBlackBox(...)
, and tomorrow -ReconstructContainerFromScratch(...)
.It completely contradicts the concept of
TDD,
in which the product design is dictated by the specification of its behavior in the form of a test suite. You will not begin development with a writing of tests forprivate
methods of nonexistent classes?:)
- The fact that at some point in time you wanted to write a test for a
private
method most likely means one of two things:
You have no tests and there is some class with a lot of responsibility. You are trying to verify the correctness of its behavior "piece by piece", for example, by starting with testing
private
methods. Correctly in this case, you need to understand what behavior is expected from the class, speculate this behavior in tests that use thepublic
interface of the class and refactor this class in order to reduce the number of its responsibilities.You have tests and it still seems to you that testing a
private
method is a good idea. In this case, most likely, the logic of theprivate
method fits in well with some separate entity and can be removed from the original class. In this case, you need to come up with a name for the new entity, specify its behavior in the tests and remove it from the original class.
- All right but off topic. If you had bothered to read my comment (to which you are answering) completely, you would understand what exactly is easier in this case to drop the testing in the Test Unit. To further confusion - renamed the topic. - Track
- one@ Kitty: I’m happy to steal the last item for future discussions. :) - VladD 4:39 pm
To begin with, the private
methods are not intended for testing. They are not part of the official "facade" of the class, they have the right to rely on invariants and preconditions to be met, but not to check them explicitly, they have the right to behave "incorrectly" when they are called within the framework of the workflow established for them.
You can, however, test internal
methods. They will be available to the test assembly if you specify the InternalsVisibleTo
attribute.
- Of course, it is stupid to cover all private fields with tests, but sometimes it can be useful. - Track
- one@Track: fields? - VladD pm
- methods of course :) - Track
The solution is to use Reflection like this:
var field = typeof(CopyItems).GetMethod(("FixRenamedPath"), BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); string targetFile = (string)field.Invoke(null, new object[] { renamedFile, relatedFile, targetDir });
- 3Perfect solution. Try now, with a set of tests written in this way, to do some Fowler refactoring such as the
Rename Method
or theIntroduce Parameter Object.
- Costantino Rupert - one@ Kitty: You would have the irony of reds. - VladD
- It's not about refactoring. Without this test, referring to the public fields, it was necessary to prepare files (delete, copy, etc.) Of course, you could copy the method somewhere else or temporarily make it public. And why all this? Just because when private methods are not taken to test? :) But it is much easier to comment out two lines. - Track
- @Track: private methods are like underwear: they are not shown to anyone. At any moment they have the right to be removed or altered, treacherously and without a declaration of war. Including them in a unit-test means that you are trying to fix their semantics, not to mention simply the presence and list of arguments. - VladD 5:48 pm
- Well, yes - I absolutely agree. But from tests it is convenient to test. Oddly enough. When the private method is tested, you can comment out the lines in the test and forget about this method. But testing is just so convenient. - Track