1

Disclaimer: the unit-test related info for this question is not really relevant - you can skip to "The Problem" if you're not familiar with this, but it helps set the context.

I have a class that I need to unit-test. It looks like this:

public class NumberParser {
    public static void CheckByteRange(string str){...}
    [...]
    public static void CheckFloatRange(string str){...}
    [...]
}

I want to use an NUnit parametrized unit-test to test all these methods. Here's the test method:

    [TestCaseSource("CheckRange_Overflow_Inputs")]
    public void CheckRange_Overflow(string value, Action<string> method)
    {
        Assert.Throws<Exception>(() => method(value));
    }

The test uses TestCaseSourceAttribute to specify a field that contains a list of sets of arguments to the test method.

Now, NUnit expects a field called CheckRange_Overflow_Inputs, of type object[], that itself contains object[] elements, each of which contains values for the arguments to the test method.

The problem:

Ideally, I'd like to write the field like this:

    private static readonly object[] CheckRange_Overflow_Inputs
        = new object[]
              {
                  new object[]{byte.MaxValue,  NumberParser.CheckByteRange },
                  [...]
                  new object[]{float.MaxValue, NumberParser.CheckFloatRange },
                  [...]
              };

But the compiler complains it can't cast a method group to an object.

That makes sense - NumberParser.CheckByteRange could be ambiguous, e.g. it could be overloaded.

But how can I get the compiler to allow me to save (as an object) the method called NumberParser.CheckByteRange that takes a string and returns void ?

What I tried (and failed succeeded):

 [...]
 new object[]{byte.MaxValue, (Action<string>)NumberParser.CheckByteRange },
 [...]
Cristian Diaconescu
  • 34,633
  • 32
  • 143
  • 233
  • Hmm, have you tried something like: `(string s) => NumberParser.CheckByteRange(s)`? It does not look that good, but maybe it will help a bit? – Jarek May 21 '13 at 09:42
  • 1
    Well, I just want to point out that this question is a joy to read :) I wish everyone was writing questions like this – Dimitar Dimitrov May 21 '13 at 09:43
  • Please can you add the exact message (copy/paste, ideally) you are getting from the compiler about this. – Marc Gravell May 21 '13 at 09:47
  • 1
    @DimitarDimitrov Thanks, I do my best. If I'm going to get free help, the least I can do is try to make it easy for the benevolent souls to help me :) – Cristian Diaconescu May 21 '13 at 09:49

1 Answers1

4

If the method was static, then your attempt would have worked. It can't work simply as

(Action<string>)NumberParser.CheckByteRange

when CheckByteRange is an instance (non-static) method because you haven't told it which instance (this) to use. So either:

  • make CheckByteRange into a static method
  • tell it which instance to use, i.e. (Action<string>)someInstance.CheckByteRange

With them static, the following compiles fine for me:

private static readonly object[] CheckRange_Overflow_Inputs
    = new object[]
          {
              new object[]{byte.MaxValue,  (Action<string>) NumberParser.CheckByteRange },
              new object[]{float.MaxValue, (Action<string>) NumberParser.CheckFloatRange },
          };
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 2
    @Cristi if I make them `static`, the code you have posted as "**What I tried** (and failed)" compiles. What error are you seeing, ***exactly***? – Marc Gravell May 21 '13 at 09:43
  • 2
    PEBKAC... The code above is contrived from the actual class I want to test. I was convinced the methods return `void`, but they don't. Changing to `(Func) NumberParser.CheckFloatRange` does the trick. – Cristian Diaconescu May 21 '13 at 09:47