Click here to Skip to main content
15,441,032 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
I just started a new job as a junior .Net developer and my first task is to cover a solution that has 80% success with unit-tests, in order to assure every piece of code is working correctly.
I was able to make it to 37% after covering all public methods by simply calling them from my tests, but I have no idea how to access private/protected methods from outside of their classes.
The catch is that I am not allowed to change any piece of the existing code.

The project is written in C# .net framework 4.7.2
For Code coverage analysis I use OpenCover
Testing framework: Nunit 3.11.0

Any advice is appreciated!

What I have tried:

I have tried to find a solution for this issue, but unfortunately, the most common advice is to simply not test Private methods.
Another alternative was changing the methods to public, but it's not an option as I am not allowed to change any piece of the existing code.
Posted
Updated 2-Apr-19 4:58am
v2
Comments
CPallini 2-Apr-19 7:46am     CRLF
"Up to a point, it is better to just let the snags [bugs] be there than to spend such time in design that there are none." --Alan M. Turing "Debugging? Klingons do not debug. Bugs are good for building character in the user." -- Klingon developers
IlanGreen 2-Apr-19 9:12am    
I do not agree with you @CPallini. Each bug you eliminate or catch in production saves you tons of time after

Our team uses Typemock's Isolator as a mocking framework and it has the ability to test private methods.

Simple Api for verifying private method calls:
Isolate.Verify.NonPublic.WasCalled(<instance>, "PrivateMethodname");
Also, you can fake private instances and change their behavior which will help you against the DB calls and all this tight dependencies

It has a disadvantage, not cheap at all but if i am not mistaken it has 7 days of free trial.
Download Isolator - Typemock[^]

hope it helps
 
Share this answer
 
Comments
IlanGreen 8-Apr-19 3:38am    
Nice! such friendly Api, easier to use than reflection with this huge amount of option.
1. please explain what this means: "a solution that has 80% success"

2. in general you do not unit test private methods; after all, by definition they are only used from the public API

3. of course, the architecture of an app can be so screwed up that you can't isolate certain classes; as you describe, you may not be allowed to change the code, etc. Unit testing can't touch structural issues that.

4. if you really have to mess around with private methods, you could use reflection: [^]

5. you could use AOP tools like PostSharp (commercial) [^], and Fody (open source) [^] to inject/weave logging code into the run-time app

I suggest you talk to your team members and/or manager, and get some clarification on what is expected of you. No one will think less of you for this !

imho, unit testing is a key part of a wider process of software qa that includes logging, identifying bottlenecks as well as bugs, performance tuning, and having real people (preferably "naive" end-users) bang away at your whatever and try to break it.
 
Share this answer
 
v3
Comments
IlanGreen 2-Apr-19 9:25am     CRLF
1.80% sequence coverage, excuse me for the typo 2.Well, I was instructed to do it, also how do you reach more than 50% code coverage at all? I mean, it is obvious that all your project cant be public 4.I will try it now, thanks for the article 5.Ill check those toold right now Thank you very much in general, you calmed me down, i was sure i am in big trouble not being able to do such easy task
The bad news is that your task is probably impossible. Unit testing isn't something you can retro-fit to an application, it has to be written with unit testing in mind. Trying to retro-fit unit testing to an app not designed for it will often lead to major refactoring of the code.

To cover your specific question though, you tend to ensure coverage in private methods by manipulating the public methods that call those methods. So if I have code like below;

public class TestClass
{
    public int Add(int x, int y)
    {
        if (!IsValid(x) || !IsValid(y))
        {
            throw new ArgumentException();
        }

        return x + y;
    }

    private bool IsValid(int number)
    {
        if (number >= 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}


I can't call IsValid directly from my unit tests, but I can make sure all paths in the function are covered by calling Add with both valid and invalid params;

[TestMethod]
public void WhenParamsValidAddReturnsSum()
{
    // Arrange
    TestClass testClass = new TestClass();

    // Act
    int result = testClass.Add(1, 2);

    // Assert
    Assert.AreEqual(3, result);
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void WhenParamsInvalidAddReturnsException()
{
    // Arrange
    TestClass testClass = new TestClass();

    // Act
    int result = testClass.Add(-1, 2);
}


Have a read through this

Unit Testing - Visual Studio | Microsoft Docs[^]
 
Share this answer
 
v2
Comments
IlanGreen 2-Apr-19 10:03am     CRLF
Thank you for the advice @F-ES Sitecore, I tried this scenario and the coverage of private bool IsValid(int number) is indeed 100% as its beings fully executed. My problem begins when this private method is accessing other places, for example a DB that cant be reached and i am not able to check this scenarios
F-ES Sitecore 2-Apr-19 10:23am    
This is the problem with trying to retro-fit unit testing. Your unit tests shouldn't require any external resources so no DB access, no network access etc. If you are testing code that requires DB access you need to abstract that access to a class that is resolved using dependency injection\IoC. That way your actual production code will get a class that reads the DB, but your unit test can inject a dummy\mocked class that returns hard-coded results rather than needing DB access. If your solution isn't coded like this then you either need to change the solution or accept the code can't be unit tested.
IlanGreen 3-Apr-19 5:39am    
Thank you very much for the input. by that you mean I must mock all dependencies of these methods in order to test it in an efficient way?
F-ES Sitecore 3-Apr-19 11:33am    
Yes, however that means the code has to get the concrete class to use from a dependency resolver which it probably doesn't do currently, which is why adding unit tests usually involves a lot of changes to the code.
You can access the private methods with reflection:

MethodInfo myPrivateMethod = typeof(MyClassBeingTested).GetMethod(
"PrivateMethodName",
"BindingFlags.NonPublic | BindingFlags.Instance);

myPrivateMethod.Invoke(
instanceOfMyClassBeingTested,
new object[] {
parameter1,
parameter2});


When I run across this kind of issue, I write a method that implements the code above and then send it all the necessary parameters. That way, I can use it several times.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900