hexcode
hexcode

Reputation: 403

How can I fake an extension method? (System.Collections.Generic.CollectionExtensions.GetValueOrDefault)

Functions I want to fake

As shown in the image, I want to fake extension method (seen in Specflow's ScenarioContext class) : public bool TryGetValue<TValue>(string key, out TValue value)

I've created fakes for the System.Collection assembly (which contains the IDictionary extension method), but I do not understand how to fake a function which has parameters. I do know how to fake for a parameterless function such as the File.IO.ReadAllLines() function :

            using (ShimsContext.Create())
            {
            System.IO.ShimFile.ReadAllLines = m => new string[]{};
            ....

Can I get help understanding how to mock this extension method: System.Collections.Generic.CollectionExtensions.GetValueOrDefault

... I honestly tried looking for examples, but the only ones I could find were parameterless functions or getters.

Upvotes: -2

Views: 640

Answers (2)

IV.
IV.

Reputation: 9471

Here's a distinction that may be of use to you: Given a choice of extensions, the compiler will choose the more-constrained version. So for example if you wantGetValueOrDefault() to return a mocked result for a SpecFlowContext then make an extension for this SpecFlowContext.

static class Extensions
{
    public static object GetValueOrDefault<TKey>(
        this SpecFlowContext dictionary, 
        TKey key) where TKey : notnull
    {
        return "Fake value A";
    }

    public static object GetValueOrDefault<TKey, TValue>(
        this SpecFlowContext dictionary, 
        TKey key, 
        [AllowNull] TValue defaultValue)
    {
        if(defaultValue is string valid)
        {
            return valid;
        }
        return "Fake value B";
    }
}

TEST

class Program
{
    static void Main(string[] args)
    {
        // Normal dictionary
        var normal = new Dictionary<string, object>
        {
            { "Apple", "Red" },
            { "Orange", "Orange" },
        };
        Console.WriteLine(normal.GetValueOrDefault("Apple"));


        // SpecFlowContext dictionary
        var fake = new CustomSpecFlowContext
        {
            { "Apple", "Red" },
            { "Orange", "Orange" },
        };
        Console.WriteLine(fake.GetValueOrDefault("Apple"));
        Console.WriteLine(fake.GetValueOrDefault("Apple", (string)null));
        Console.WriteLine(fake.GetValueOrDefault("Apple", "Fake value C"));
    }
}
// Class that implements abstract SpecFlowCOntext
class CustomSpecFlowContext : SpecFlowContext { }

console output

Upvotes: 0

JonasH
JonasH

Reputation: 36659

I would assume you are talking about Microsoft Fakes.

To provide a fake implementation of a method with parameters the documentation specifies the following:

Name is original name + parameter types:

So for ReadAllLines I would expect the name to be ReadAllLinesString. Your editor should be able to show you what delegates are available to assign to.

But this is not an extension method, just a regular static method. You would typically not mock extension methods, since these are just providing extra functionality. Mock the underlying type instead.

In the case of CollectionExtensions.GetValueOrDefault I would argue that you should mock the underlying Dictionary.TryGetValue that I assume GetValueOrDefault uses. I would however argue that faking or mocking collections is not very useful. Mocking tend to be most useful when used on the "edges" of some module, like replacing file system functions as an example. Collections are a fairly integral part of .Net, so there is much less to be gained by trying to mock them, IMHO.

Upvotes: 1

Related Questions