Welcome to Typemock Answers. Here you can ask and receive answers from other community members. And if you liked or disliked an answer or thread: react with an up- or downvote Enjoy!

Transient Isolate.Fake.AllInstances<Dependency>()

+3 votes
Hi all,

It appears that, after calling Isolate.Fake.AllInstances<Dependency>(), everytime Dependency is instantiated, it points to the same fake Dependency (i.e. singleton). Does anyone know of a way to have it create distinct objects (i.e. transient)?

Thanks,

Chris
asked Oct 20 by chrisv (150 points)

1 Answer

+1 vote

Hi Chris,

Isolate.Fake.AllInstances<Dependency>() returns an object on which you can set the desired behavior.

Everytime Dependency is instantiated it will point to this object.

Can you please send an example and tell me what you are trying to do?

Cheers,

Sapir.

answered Oct 22 by SapirTypemock (1,130 points)

Hi Sapir,

The issue is that each member of the list dependencies points to the same fake instance. The output demonstrates this; we see the same number repeated 50 times. How do we get each member to point to a different fake instance? In other words, I want to see 50 different numbers in the output.

Regards,

Chris

 

public void Test()
{
    Isolate.Fake.AllInstances<Dependency>();

    List<Dependency> dependencies = new List<Dependency>();
    Random random = new Random();
    Enumerable.Range(0, 50).ToList().ForEach(i =>
    {
        dependencies.Add(new Dependency() { DependencyState = random.Next() });
    });

    dependencies.ForEach(d =>
    {
        Debug.WriteLine(d.DependencyState);
    });
}

public class Dependency
{
    public int DependencyState { get; set; }
}

 

Hey Chris,

We will investigate whether we can make Isolate.Fake.AllInstances create distinct objects, and make it a Typmeock feature in the future. 
I will keep you updated.

Meanwhile, you can use Isolate.Fake.NextInstance<T>():


        public void Test()
        {
            List<Dependency> dependencies = new List<Dependency>();
            Random random = new Random();

            Enumerable.Range(0, 50).ToList().ForEach(i =>
            {
                Isolate.Fake.NextInstance<Dependency>();
                dependencies.Add(new Dependency() { DependencyState = random.Next() });
            });

            dependencies.ForEach(d =>
            {
                Debug.WriteLine(d.DependencyState);
            });
        }
 
You can read more about it here
 
Cheers,
Sapir. 

Unfortunately, NextInstance will not work for my purposes. Although it works for my original code snippet, it does not work for my actual use-case. Here is another code snippet that better reflects my actual use-case. You will see that ClassUnderTest instantiates Dependency multiple times. NextInstance will only mock the first one, and subsequent ones will not get mocked. See the following example:

public void Test()
{
    Enumerable.Range(0, 5).ToList().ForEach(i =>
    {
        var fake = Isolate.Fake.NextInstance<Dependency>();
        Isolate.WhenCalled(() => fake.DependencyMethod()).DoInstead(c =>
        {
            Debug.WriteLine($"Mocked = {((Dependency)c.Instance).DependencyState}");
        });

        new ClassUnderTest().ClassUnderTestMethod();
    });

    //Outputs the following:
    //Mocked = 153
    //Not Mocked = 860
    //Mocked = 530
    //Not Mocked = 157
    //Mocked = 592
    //Not Mocked = 323
    //Mocked = 125
    //Not Mocked = 221
    //Mocked = 441
    //Not Mocked = 538
}

public class ClassUnderTest
{
    private static Random random = new Random();

    private List<Dependency> Dependencies { get; } = Enumerable.Range(0, 2).Select(i => new Dependency { DependencyState = random.Next(100, 1000) }).ToList();

    public void ClassUnderTestMethod() => Dependencies.ForEach(d => d.DependencyMethod());
}

public class Dependency
{
    public int DependencyState { get; set; }

    public void DependencyMethod() => Debug.WriteLine($"Not Mocked = {DependencyState}");
}

 

And just for thoroughness, I will repeat the original issue with AllInstances. See the following example. Notice that there are repeated values in the output (Actually, I am surprised to find some variabilty. Even so, I need 100% variability).

public void Test()
{
    var fake = Isolate.Fake.AllInstances<Dependency>();
    Isolate.WhenCalled(() => fake.DependencyMethod()).DoInstead(c =>
    {
        Debug.WriteLine($"Mocked = {((Dependency)c.Instance).DependencyState}");
    });

    Enumerable.Range(0, 5).ToList().ForEach(i =>
    {
        new ClassUnderTest().ClassUnderTestMethod();
    });

    //Outputs the following:
    //Mocked = 198
    //Mocked = 198
    //Mocked = 159
    //Mocked = 159
    //Mocked = 349
    //Mocked = 349
    //Mocked = 754
    //Mocked = 754
    //Mocked = 148
    //Mocked = 148
}

public class ClassUnderTest
{
    private static Random random = new Random();

    private List<Dependency> Dependencies { get; } = Enumerable.Range(0, 2).Select(i => new Dependency { DependencyState = random.Next(100, 1000) }).ToList();

    public void ClassUnderTestMethod() => Dependencies.ForEach(d => d.DependencyMethod());
}

public class Dependency
{
    public int DependencyState { get; set; }

    public void DependencyMethod() => Debug.WriteLine($"Not Mocked = {DependencyState}");
}

 

So, in conclusion, it would be helpful for AllInstances to optionally create distinct objects.

I good example is Microsoft.Extensions.DependencyInjection.ServiceCollection, which has methods AddTransient, AddScoped, AddSingleton.

Thank you for helping.

Hey Chris,

You can try writing your test like this:

        [TestMethod, Isolated]
        public void Test()
        {
            List<Dependency> dependencyList = new List<Dependency>();
            Enumerable.Range(0, 5).ToList().ForEach(i =>
            {

                Enumerable.Range(0, 2).ToList().ForEach(j =>
                {
                    var fake = Isolate.Fake.NextInstance<Dependency>();
                    Isolate.WhenCalled(() => fake.DependencyMethod()).DoInstead(c =>
                    {
                        Console.WriteLine($"Mocked = {((Dependency)c.Instance).DependencyState}");
                    });
                    dependencyList.Add(fake);
                }

                );
                new ClassUnderTest().ClassUnderTestMethod();

            });
        }

This way, each one of the "Dependency" objects in the "ClassUnderTest" object will be faked. 

Please let me know if it helps.

Cheers,

Sapir.

I am surpised it works! This is the order of events in your sample code. It somehow fakes both Dependencies (3 & 4).

  1. NextInstance<Dependency>
  2. NextInstance<Dependency>
  3. Instantiate Dependency
  4. Instantiate Dependency

I would have expected that the correct order is:

  1. NextInstance<Dependency>
  2. Instantiate Dependency
  3. NextInstance<Dependency>
  4. Instantiate Dependency

Isn't this surprising? By the way, thank you for your help, Sapir.

Hey Chris,

That's not a problem at all! I'm happy to help :)

In my opinion, the order of events is not surprising, because first we use NextInstnace and only when "ClassUnderTest" object is created the two "Dependency" objects are instantiated and faked.

I hope it helps.

Cheers,

Sapir.
...