Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call times verification change from 4.11.0 #990

Closed
Caraul opened this issue Apr 3, 2020 · 5 comments
Closed

Call times verification change from 4.11.0 #990

Caraul opened this issue Apr 3, 2020 · 5 comments

Comments

@Caraul
Copy link
Contributor

Caraul commented Apr 3, 2020

Repro 4.13.1:

		public interface IRet<T>
		{
		}

		public interface IXyz
		{
			IRet<T> M<T>();
		}

		public class A
		{
		}

		public class B : A
		{
		}

		var mock = new Mock<IXyz>();
		mock.Setup(xyz => xyz.M<A>()).Returns((IRet<A>)null);
		mock.Setup(xyz => xyz.M<B>()).Returns((IRet<B>)null);

		mock.Object.M<A>();
		mock.Object.M<B>();

		mock.Verify(xyz => xyz.M<A>(), Times.Once);

throws:
Expected invocation on the mock once, but was 2 times: xyz => xyz.M<Program.A>()

Performed invocations:

MockProgram.IXyz:1 (xyz):

  Program.IXyz.M<Program.A>()
  Program.IXyz.M<Program.B>()

Works in 4.11.0 - looks like in 4.11.0 Moq also took in account return types during verification. Is it intended behaviour change?

@stakx
Copy link
Contributor

stakx commented Apr 5, 2020

Possibly related to #904. If so (I haven't yet had time to look at this in-depth), then the change would be intended.

@Caraul
Copy link
Contributor Author

Caraul commented Apr 6, 2020

Great point, definitely with no doubt as "Moq no longer considers the return type as part of a method's signature like it used to (and that is generally a good thing)". The only thing I'd like to clear - if we have void M<T>() and call it as M<A>() and M<B>() where A is the base class for B (like in repro above). Should such calls be treated and counted differently? Yet in 4.11.0 M<A>() and M<B>() both must be setup but then Verify(M<A>()) includes all M<B>() calls:

		public interface IXyz
		{
			void M<T>();
		}

		public class A
		{
		}

		public class B : A
		{
		}

		var mock = new Mock<IXyz>();
		mock.Setup(xyz => xyz.M<A>());
		mock.Setup(xyz => xyz.M<B>());

		mock.Object.M<A>();
		mock.Object.M<B>();

		mock.Verify(xyz => xyz.M<A>(), Times.Once);

also fails with

Expected invocation on the mock once, but was 2 times: xyz => xyz.M<Program.A>()

@stakx
Copy link
Contributor

stakx commented Apr 18, 2020

@Caraul, what about the following scenario:

public interface IFruit { }
public class Apple : IFruit { }
public class Banana : IFruit { }

public interface IEat
{
    void Eat<T>(T item);
}

var stakxMock = new Mock<IEat>();
var stakx = stakxMock.Object;

stakx.Eat(new Apple());
stakx.Eat(new Banana());

stakxMock.Verify(s => s.Eat(It.IsAny<IFruit>()), Times.Exactly(2));

Here we verify that I ate any two fruit. Since I ate one apple and one banana (both of which are fruit), I believe verification should pass.

However, if we went along with your suggestion, verification would fail because I didn't eat two abstract fruit; I ate a concrete apple and a concrete banana. That doesn't really make much sense in my book.

@stakx
Copy link
Contributor

stakx commented Apr 18, 2020

P.S.: I believe you could define a custom type matcher (those were introduced with version 4.13) to match a precise type while excluding its subtypes; see #908.

@Caraul
Copy link
Contributor Author

Caraul commented Apr 20, 2020

As being a monkey some millenniums ago I have to agree :) Closing this issue, thanks for pointing out to custom type matchers.

@Caraul Caraul closed this as completed Apr 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants