chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes
The below code will not work:

            var envs = new List<Environment>();
            var genFormSet = Isolate.Fake.Instance<EnvironmentSettingsCollection>();
            Isolate.WhenCalled(() => genFormSet.SingleOrDefault(s => s.Name == "Database")).WillReturn(Isolate.Fake.Instance<EnvironmentSetting>());
            Isolate.WhenCalled(() => genFormSet.SingleOrDefault(s => s.Name == "LogPath")).WillReturn(Isolate.Fake.Instance<EnvironmentSetting>());
            Isolate.WhenCalled(() => genFormSet.SingleOrDefault(s => s.Name == "ExportPath")).WillReturn(Isolate.Fake.Instance<EnvironmentSetting>());
            envs.Add(new Environment("MyMachine", "TestEnvironment", genFormSet));

            var nonGenFormSet = Isolate.Fake.Instance<EnvironmentSettingsCollection>();
            Isolate.WhenCalled(() => nonGenFormSet.SingleOrDefault(s => s.Name == "Databse")).WillReturn(null);
            Isolate.WhenCalled(() => nonGenFormSet.SingleOrDefault(s => s.Name == "LogPath")).WillReturn(null);
            Isolate.WhenCalled(() => nonGenFormSet.SingleOrDefault(s => s.Name == "ExportPath")).WillReturn(null);
            envs.Add(new Environment("SomeOtherMachine", "TestEnvironment", nonGenFormSet));

            Assert.IsNotNull(genFormSet.SingleOrDefault(s => s.Name == "Database"));
            Assert.IsNull(nonGenFormSet.SingleOrDefault(s => s.Name == "Database"));

The second assert will not hold. How can I isolate a method call like SingleOrDefault(s => s.Name == "foo").WillReturn(null)?
asked by halcwb (5.5k points)

1 Answer

0 votes

The reason for that behavior is Isolator default sequencing behavior. This behavior makes a list of sequential WhenCalled's return their result after each other. This behavior is applied on any method recording unless used WithExactArguments.

Example for simple sequence:
ClassToFake fake = Isolate.Fake.Instance<ClassToFake>();
Isolate.WhenCalled(() => fake.GetNum()).WillReturn(1);
Isolate.WhenCalled(() => fake.GetNum()).WillReturn(2);

Assert.That(fake.GetNum(), Is.EqualTo(1));
Assert.That(fake.GetNum(), Is.EqualTo(2));

Example for sequence with respect to arguments:
ClassToFake fake = Isolate.Fake.Instance<ClassToFake>();
Isolate.WhenCalled(() => fake.Translate("One")).WithExactArguments().WillReturn(1);
Isolate.WhenCalled(() => fake.Translate("Two")).WithExactArguments().WillReturn(2);

Assert.That(fake.Translate("Two"), Is.EqualTo(2));
Assert.That(fake.Translate("One"), Is.EqualTo(1));

In the original posted case there's no usage of WithExactArguments. There's still a problem since the argument type if Func<string, bool> which doesn't implement equality members. There are two possible workarounds -

In this case we ignore the arguments and make the test dependent on a specific calls order by the production code. The advantage of this is that it's very simple, but it is a little fragile.

Another workaround is to create a wrapper method which receives string argument and its body performs the "real" filtering. In the production replace the calls to SingleOrDefault with the new method in the test replace the faking behavior with the new method.

Please let me know if it helps.

Typemock Support
answered by Elisha (12k points)