1

I'm developing a C# library with .NET Framework 4.7.1 and Visual Studio 2017.

I want to test this method:

private void AddProductionRule(
    string bnfLine,
    Dictionary<string, string[]> productionRules)
{
    if (productionRules == null)
        productionRules = new Dictionary<string, string[]>();

    string[] stringSplitted = bnfLine.Split(new[] { "::=" }, StringSplitOptions.None);

    string key = stringSplitted[0].Trim();
    string[] rules;

    stringSplitted[1] = Regex.Replace(stringSplitted[1], "[::=\r\n]", string.Empty).Trim();

    rules = stringSplitted[1].Split('|').Select(rule => rule.Trim()).ToArray();

    productionRules.Add(key, rules);
}

With this Nunit method:

[Test]
public void ShouldAddProductionRule()
{
    // Arrange
    PrivateObject privateObject = new PrivateObject(grammar);

    string line = "<expr> ::= <expr><op><expr>\r\n| (<expr><op><expr>)\r\n| <pre_op>(<expr>)\r\n| <var>";
    Dictionary<string, string[]> expectedRules = new Dictionary<string, string[]>
    {
        { "<expr>", new string[] { "<expr><op><expr>", "(<expr><op><expr>)", "<pre_op>(<expr>)", "<var>" } }
    };
    Dictionary<string, string[]> actualRules = null;

    object[] args = new object[2] { line, actualRules };

    // Act
    privateObject.Invoke("AddProductionRule", args);

    actualRules = args[1] as Dictionary<string, string[]>;

    // Assert
    NUnit.Framework.CollectionAssert.AreEqual(expectedRules, actualRules);
}

But it fails because actualRules remains as null and I don't know how to get the value of productionRules dictionary from a PrivateObject (Nuget <package id="Microsoft.VisualStudio.QualityTools.UnitTestFramework.Updated" version="15.0.26228" targetFramework="net471" />).

If I add out to the parameter, I get an error here: if (productionRules == null). I think the method should work because productionRules is a reference.

I've thought to return the Key, Value pair from the method but I don't know how to declare it.

How can I test this method with PrivateObject?

VansFannel
  • 45,055
  • 107
  • 359
  • 626
  • 1
    The assignment of `productionRules` will not assign the passed argument. – CodeCaster Mar 26 '18 at 13:58
  • 1
    This appears to be an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) especially as you are trying to test a private method. Are there not any public members that access the private method and can be used to verify that it behaves as desired. This is a design issue that is being mistaken as a testing tool issue. – Nkosi Mar 26 '18 at 13:58
  • @Nkosi Yes, there is a method that will call this private method, but it also calls another methods. This is why I have created this test. – VansFannel Mar 26 '18 at 14:01
  • The problem encountered with this test is revealing the issues with the current design. If you are unable to test in isolation without knock on effects then your code is tightly coupled to concerns that should abstracted and refactored. – Nkosi Mar 26 '18 at 14:03
  • @Nkosi Yes, I think so. I'm going to modify the method to return a key, value tuple. – VansFannel Mar 26 '18 at 14:04
  • Everything in that method can be extracted into its own service and injected back into the target class. The method does not appear to depend on anything in the current class it is defined in. – Nkosi Mar 26 '18 at 14:08

0 Answers0