简体   繁体   中英

unit testing c# and issue with testing a private method

I want to test GetParameters() to assert the returned value includes "test=" within the value. Unfortunately the method responsible for this is private. Is there a way I can provide test coverage for this? The problem I have is highlighted below:

if (info.TagGroups != null)

The problem is that info.TagGroups equals null in my test

Thanks,

Test

[Test]
public void TestGetParameters()
{
    var sb = new StringBuilder();
    _renderer.GetParameters(sb);
    var res = sb.ToString();
    Assert.IsTrue(res.IndexOf("test=") > -1, "blabla");
}   

Implementation class to test

internal void GetParameters(StringBuilder sb)
{
    if (_dPos.ArticleInfo != null)
    {
        var info = _dPos.ArticleInfo;

        AppendTag(sb, info);

    }
}

private static void AppendTag(StringBuilder sb, ArticleInfo info)
{
    if (info.TagGroups != null)  // PROBLEM - TagGroups in test equals null
    {
        foreach (var tGroups in info.TagGroups)
        {
            foreach (var id in tGroups.ArticleTagIds)
            {
                sb.AppendFormat("test={0};", id);
            }
        }
    }
}

Testing private methods directly (as opposed to indirectly through your class's public API) is generally a bad idea. However, if you need to, you can do this via reflection.

A better choice would be to refactor your code to be more testable. There are any number of ways to do this, here's one option:

It looks like the logic you want to test is in AppendTag . This is a static method, and doesn't modify any state, so why not make it public and callable by tests directly?

In the same way, you could also make GetParameters public static by giving it an additional ArticleInfo parameter.

You can make internals visible to your testing project: in AssemblyInfo use InternalsVisibleToAttribute .


DISCLAIMER:
Testing private/internal methods is bad! It's not TDD and in most cases this is a sign to stop and rethink design.
BUT in case you're forced to do this (legacy code that should be tested) - you can use this approach.

Yes, you need just to inject appropriate contents of _dPos.ArticleInfo into your class. This way you can ensure that all paths will be covered in the private method. Another possibility is to rewrite this simple code using TDD - this will give you nearly 100% coverage.

Also note, that in general you shouldn't really care about how the private method works. As long as your class exposes desired behavior correctly everything is fine. Thinking too much about internals during testing makes your tests coupled with the details of your implementation and this makes tests fragile and hard to maintain.

See this and this for example, on why not to test implementation details.

UPDATE :

I really don't get why people always go with the InternalsVisible approach and other minor arguments encouraging testing of private methods. I'm not saying that it's always bad. But most of the time it's bad . The fact that some exceptional cases exist that force you to test private methods doesn't mean that this should be advised in general. So yes, do present a solution that makes testing implementation details possible, but after you've describes what is a valid approach in general. There are tons of blog posts and SO questions on this matter, why do we have to go through this over and over again? (Rhetorical question).

In your properties/assemblyinfo.cs add:

  [assembly: InternalsVisibleTo("**Insert your test project here**")]

EDIT Some people like testing internals and private methods and others don't. I personally prefer it and therefor I use InternalsVisibleTo. However, Internals are internal for a reason and this should therefore be used with caution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM