DefaultValue.Empty vs "enumerables", and the use of SetReturnsDefault
Describe the Bug
Firstly, DefaultValue.Empty is described as: "Default behavior, which generates ... empty array and enumerables ...."
It may be a matter of semantics but I expected something like a List<T> to be also treated as "enumerables" in this context. Depending on point of view, applying this to everything implementing IEnumerable<T> may be too much (should a string be "empty" or "null" in this mode?) but how about everything related to ICollection<T>?
If nothing else, I hope this post will help others who encounter the same issue and wonder how to "make it work" (without explicit Setup for each such method on a mock).
Secondly, SetReturnsDefault - it's currently very "picky" ;)
It would be nice, IMHO, if it automatically supported all derived types... and/or wrapped in a Task, ValueTask.
Steps to Reproduce
This (MSTest-style) test code should explain it all:
[TestClass]
public class DefaultValue_Empty_Enumerables
{
public interface IFoo
{
int[] GetArray();
IEnumerable<int> GetIEnumerable();
ICollection<int> GetICollection();
IList<int> GetIList();
List<int> GetList();
Task<int> GetArrayAsync();
Task<List<int>> GetListAsync();
}
[TestMethod]
public void AllThoseTypesCanBeCalled_Enumerables()
{
Assert.IsTrue(typeof(int[]).IsAssignableTo(typeof(IEnumerable<int>)));
Assert.IsTrue(typeof(ICollection<int>).IsAssignableTo(typeof(IEnumerable<int>)));
Assert.IsTrue(typeof(IList<int>).IsAssignableTo(typeof(IEnumerable<int>)));
Assert.IsTrue(typeof(List<int>).IsAssignableTo(typeof(IEnumerable<int>)));
Assert.IsTrue(typeof(string).IsAssignableTo(typeof(IEnumerable<char>)), "something to watch out for");
Assert.IsFalse(typeof(string).IsAssignableTo(typeof(ICollection<char>)), "a more specific workaround?");
}
[TestMethod]
public void UsingDefaultMoqSettings_DefaultValue_Empty()
{
var mock = new Mock<IFoo>();
Assert.AreEqual(DefaultValue.Empty, mock.DefaultValue);
}
[TestMethod]
public async Task MethodsWithTheseReturnTypes_DefaultToEmpty()
{
var mock = new Mock<IFoo>();
Assert.IsNotNull(mock.Object.GetArray());
Assert.IsNotNull(mock.Object.GetIEnumerable());
Assert.IsNotNull(await mock.Object.GetArrayAsync());
}
[TestMethod]
public async Task MethodsWithTheseReturnTypes_DefaultToNull()
{
var mock = new Mock<IFoo>();
Assert.IsNull(mock.Object.GetICollection());
Assert.IsNull(mock.Object.GetIList());
Assert.IsNull(mock.Object.GetList());
Assert.IsNull(await mock.Object.GetListAsync());
}
[TestMethod]
public async Task MakingItAllWork_Almost()
{
var mock = new Mock<IFoo>();
mock.SetReturnsDefault<ICollection<int>>([]);
mock.SetReturnsDefault<IList<int>>([]);
mock.SetReturnsDefault<List<int>>([]);
Assert.IsNotNull(mock.Object.GetICollection());
Assert.IsNotNull(mock.Object.GetIList());
Assert.IsNotNull(mock.Object.GetList());
Assert.IsNull(await mock.Object.GetListAsync());
}
[TestMethod]
public async Task MakingItAllWork_IncludingAsync()
{
var mock = new Mock<IFoo>();
mock.SetReturnsDefault<ICollection<int>>([]);
mock.SetReturnsDefault<IList<int>>([]);
mock.SetReturnsDefault<List<int>>([]);
mock.SetReturnsDefault(Task.FromResult(new List<int>()));
Assert.IsNotNull(mock.Object.GetICollection());
Assert.IsNotNull(mock.Object.GetIList());
Assert.IsNotNull(mock.Object.GetList());
Assert.IsNotNull(await mock.Object.GetListAsync());
}
[TestMethod]
public void BTW_WatchOutForReset_ItResetsTheDefaultSettingsAsWell()
{
var mock = new Mock<IFoo>();
mock.SetReturnsDefault<List<int>>([]);
Assert.IsNotNull(mock.Object.GetList());
mock.Reset();
Assert.IsNull(mock.Object.GetList());
mock.SetReturnsDefault<List<int>>([]);
Assert.IsNotNull(mock.Object.GetList());
}
}
Version Info
Moq v4.20.70
I think SetReturnsDefault<T> satisfies specific needs already, without introducing the potential for severe breaking changes if the current behavior were modified. I don't think that will happen.
Due to lack of recent activity, this issue has been labeled as 'stale'. It will be closed if no further activity occurs within 30 more days. Any new comment will remove the label.
This issue will now be closed since it has been labeled 'stale' without activity for 30 days.
