"Invalid Callback" in NonVoidSetupPhrase.Returns -> ValidateCallbackReturnType is not informative or actionable
.NET version: .NET 6 Test Context: XUnit Moq: 4.8.12
Summary: Following these examples SO: https://stackoverflow.com/questions/45558470/how-do-i-go-about-unit-testing-with-entity-framework-and-moq Doc: https://learn.microsoft.com/en-us/ef/ef6/fundamentals/testing/mocking
'Invalid callback. Setup on method with return type 'EntityEntry<Foo>' cannot invoke callback with return type 'Foo'.'
at Moq.MethodCall.ValidateCallbackReturnType(MethodInfo callbackMethod, Type expectedReturnType)
at Moq.MethodCall.<>c__DisplayClass23_0.<SetReturnComputedValueBehavior>g__ValidateCallback|4(Delegate callback)
at Moq.MethodCall.SetReturnComputedValueBehavior(Delegate valueFactory)
at Moq.Language.Flow.NonVoidSetupPhrase`2.Returns(Delegate valueFunction)
at <test>
Is thrown immediately on execution, with the message
Setup on method with return type 'EntityEntry<Foo>' cannot invoke callback with return type 'Foo'
Expected: Label, name, method, property, field, class, or any other source of the offending issue.
Actual:
Exception Is devoid of any actionable or useful information, as there is no indication or reference to EntityEntry<T> or EntityEntry<Foo in this context.
Details:
[Fact]
public void foo()
{
//arrange
var mockFf = new MockDbSet<Foo>(); //Throws immediately on construction
}
with
public class MockDbSet<TEntity> : Mock<DbSet<TEntity>> where TEntity : class
{
public MockDbSet(List<TEntity> dataSource = null)
{
var data = (dataSource ?? new List<TEntity>());
var queryable = data.AsQueryable();
this.As<IQueryable<TEntity>>().Setup(e => e.Provider).Returns(queryable.Provider);
this.As<IQueryable<TEntity>>().Setup(e => e.Expression).Returns(queryable.Expression);
this.As<IQueryable<TEntity>>().Setup(e => e.ElementType).Returns(queryable.ElementType);
this.As<IQueryable<TEntity>>().Setup(e => e.GetEnumerator()).Returns(() => queryable.GetEnumerator());
//Mocking the insertion of entities
this.Setup(_ => _.Add(It.IsAny<TEntity>())).Returns((TEntity arg) => {
data.Add(arg);
return arg;
});
//...the same can be done for other members like Remove
} //Debug call stack is here
}
and Foo as
public class Foo
{
[Key]
public int Id { get; set; }
public DateTime CreatedDate { get; set; }
[MaxLength(36), Required]
public string CreatedByUserId { get; set; }
public Employee CreatedByUser { get; set; }
public DateTime? ModifiedDate { get; set; }
[MaxLength(36)]
public string ModifiedByUserId { get; set; }
public Employee ModifiedByUser { get; set; }
[Required]
public string Name { get; set; }
[MaxLength(10)]
public string ReferenceNumber { get; set; }
public int? BazId { get; set; }
public Baz Baz { get; set; }
public ICollection<Bar> Bars{ get; set; }
}
I agree, the exception message could be more helpful in this case.
} //Debug call stack is here
(This is surprising, and unfortunate. Why would the Visual Studio debugger do that? If it actually mentioned the correct line of code in the stack trace, we wouldn't need to be more specific in the exception message, because you could simply look at where code execution stopped... but given this weird quirk, what you're requesting makes sense.)
It should be relatively easy to either mention the name of the method being set up in the exception message (perhaps along with its full signature):
Invalid callback. Setup for method '
Add' (having return type 'EntityEntry<Foo>') cannot invoke callback with return type 'Foo'.
(I've rephased a few other bits and pieces here because I find the grammar of the original exception message somewhat cryptic.)
Or we could reproduce the setup's full expression:
Invalid callback. The method being set up by '
_ => _.Add(It.IsAny<Foo>())' has return type 'EntityEntry<Foo>', but the callback has return type 'Foo'.
Any thoughts?
All sound useful, I don't have a strong background in testing, this is part of an initiative to fix that, so I'm not sure what would be more beneficial to a common user.
Naively, minimum most useful would be property and type information, if not the line itself in source.
Just something to orient until getting your feet under you with Moq's nuancds
On Tue, Dec 13, 2022, 3:12 PM Dominique Schuppli @.***> wrote:
I agree, the exception message could be more helpful in this case.
} //Debug call stack is hereThis is surprising, and unfortunate. Why would the Visual Studio debugger do that? If it actually mentioned the correct line of code in the stack trace, we wouldn't need to be more specific in the exception message, because you could simply look at where code execution stopped... but given this weird quirk, what you're requesting makes sense.
It should be relatively easy to either mention the name of the method being set up in the exception message (perhaps along with its full signature):
Invalid callback. Setup for method 'Add' (having return type ' EntityEntry<Foo>') cannot invoke callback with return type 'Foo'.
(I've rephased a few other bits and pieces here because I find the grammar of the original exception message somewhat cryptic.)
Or we could reproduce the setup's full expression:
Invalid callback. The method being set up by '_ => _.Add(It.IsAny<Foo>())' has return type 'EntityEntry<Foo>', but the callback has return type 'Foo '.
Any thoughts?
— Reply to this email directly, view it on GitHub https://github.com/moq/moq4/issues/1297#issuecomment-1349626082, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAYR7G5W2LKUW4UAFQRL4ZTWNDKCNANCNFSM6AAAAAASABXVHA . You are receiving this because you authored the thread.Message ID: @.***>
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.
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.
