2

NUnit 3.4.1, JustMock 2016.2.713.2

I have the class under test:

public class AppManager {
    public string[] GetAppSets() => Registry.LocalMachine
        .OpenSubKey(@"SOFTWARE\Autodesk\AutoCAD", false)
        ?.GetSubKeyNames();
}

Also, I have the test for GetAppSets method:

[Test]
public void GetAppSets_Returns_ValidValue() {

    const string subkey = @"SOFTWARE\Autodesk\AutoCAD";
    /* The sets of applications which are based on 
     * AutoCAD 2009-2017. */
    string[] fakeSets = new[] { "R17.2", "R18.0",
        "R18.1", "R18.2", "R19.0", "R19.1", "R20.0",
        "R20.1","R21.0" };

    RegistryKey rk = Mock.Create<RegistryKey>();

    Mock.Arrange(() => rk.GetSubKeyNames()).Returns(
        fakeSets);

    Mock.Arrange(() => Registry.LocalMachine.OpenSubKey
    (subkey, false)).Returns(rk);

    AppManager appMng = new AppManager();
    string[] appSets = appMng.GetAppSets();

    Assert.AreEqual(fakeSets, appSets);
}

It works. But my test will be failure if GetAppSets method uses "Software\Autodesk\AutoCAD" or "software\autodesk\autocad" string instead of "SOFTWARE\Autodesk\AutoCAD": the appSets variable will be null if string case will be changed (because that registry key doesn't exist on my computer).

So, at this case either tester needs to know theGetAppSets method implementation (the bad variant), or to handle parameter like the case insensitive string.

Is it possible to use the second variant?

Andrey Bushman
  • 11,712
  • 17
  • 87
  • 182

2 Answers2

1

Answer to original question:

You can use an overloaded version of equality assertion.

Assert.AreEqual(fakeSets, appSets, true);

Signature:

public static void AreEqual(
string expected,
string actual,
bool ignoreCase)

Source: https://msdn.microsoft.com/en-us/library/ms243448.aspx

Answer to updated question:

for(int i = 0; i < appSets.Length, i++)
{   // If there is mismatch in length Exception will fail the test.
    Assert.AreEqual(fakeSets[i], appSets[i], true);
}
Karolis Kajenas
  • 1,523
  • 1
  • 15
  • 23
  • No, my problem is other. The `appSets` will be `null` if string case will be changed (because that registry key doesn't exist on my computer). I added this addition info into my topic right now. – Andrey Bushman Aug 09 '16 at 10:13
  • I see your point. It is a unit-test as stated in your tags, thus interaction with other components such as registry is permitted. Use a mock for GetAppSets as well. – Karolis Kajenas Aug 09 '16 at 10:16
  • I use a mock for my `GetAppSets` in my test. I use NUnit and JustMock frameworks. – Andrey Bushman Aug 09 '16 at 10:18
  • @AndreyBushman You cannot mock concrete implementations. Take a look http://stackoverflow.com/a/37194417/5505949 – Karolis Kajenas Aug 09 '16 at 10:22
  • Thank you. Also I have the remark to your answer (about third parameter): I compare two string arrays instead of two strings in my test. – Andrey Bushman Aug 09 '16 at 10:45
  • For comparring two strings NUnit has also such method: `StringAssert.AreEqualIgnoringCase("string1", "string2");`, but I need to compare two string arrays. – Andrey Bushman Aug 09 '16 at 10:48
0

It seems that the answer by @Karolis misses the point of the question.

The correct solution is to use a matcher in the arrangement to match the key in a case-insensitive manner:

    var mock = Mock.Create<RegistryKey>();
    Mock.Arrange(() => Registry.LocalMachine.OpenSubKey(
        Arg.Matches<string>(s => StringComparer.OrdinalIgnoreCase.Equals(s, @"SOFTWARE\Autodesk\AutoCAD")),
        Arg.AnyBool)
    ).Returns(mock);


    var mockKey = Registry.LocalMachine.OpenSubKey(@"software\autodesk\autocad", false);

In the above mockKey will be the same instance as mock, because of the argument matcher on the first argument.

Stefan Dragnev
  • 14,143
  • 6
  • 48
  • 52