public interface IDatabase
{
void BeginTransaction();
void CommitTransaction();
void RollbackTransaction();
void Save(int number);
}
public class DataAccess
{
private readonly IDatabase database;
public DataAccess(IDatabase database)
{
this.database = database;
}
public void CorrectSave(int number)
{
try
{
this.database.BeginTransaction();
this.database.Save(number);
this.database.CommitTransaction();
}
catch (InvalidOperationException)
{
this.database.RollbackTransaction();
}
}
public void IncorrectSave(int number)
{
try
{
this.database.Save(number);
this.database.BeginTransaction();
this.database.CommitTransaction();
}
catch (InvalidOperationException)
{
this.database.RollbackTransaction();
}
}
}
public class DataAccessTest { private readonly Mock<IDatabase> database; private readonly DataAccess testee;
public DataAccessTest()
{
this.database = new Mock<IDatabase>(MockBehavior.Strict);
this.testee = new DataAccess(this.database.Object);
}
[Fact]
public void CorrectSave()
{
var sequence = new MockSequence();
this.database.InSequence(sequence).Setup(d => d.BeginTransaction());
this.database.InSequence(sequence).Setup(d => d.Save(It.IsAny<int>()));
this.database.InSequence(sequence).Setup(d => d.CommitTransaction());
Assert.ShouldNotThrow(() => this.testee.CorrectSave(1));
}
[Fact]
public void IncorrectSave()
{
var sequence = new MockSequence();
this.database.InSequence(sequence).Setup(d => d.BeginTransaction());
this.database.InSequence(sequence).Setup(d => d.Save(It.IsAny<int>()));
this.database.InSequence(sequence).Setup(d => d.CommitTransaction());
Assert.Throws<MockException>(() => this.testee.IncorrectSave(1));
}
}
Comment #1
Posted on Nov 20, 2010 by Helpful WombatI also noticed the same problem, here is another test case (a slightly modified version of the original sequence test cases). I am really looking forward to this feature being fixed.
[TestMethod]
public void ThisShouldWork() {
var a = new Mock<IFoo>(MockBehavior.Strict);
MockSequence t = new MockSequence();
a.InSequence(t).Setup(x => x.M(100)).Returns(101);
a.InSequence(t).Setup(x => x.M(200)).Returns(201);
a.Object.M(100);
a.Object.M(200);
}
[TestMethod]
public void ThisShouldNotWork() {
var a = new Mock<IFoo>(MockBehavior.Strict);
MockSequence t = new MockSequence();
a.InSequence(t).Setup(x => x.M(100)).Returns(101);
a.InSequence(t).Setup(x => x.N(100)).Returns(201);
a.Object.N(100);
a.Object.M(100);
}
public interface IFoo {
int M(int p);
int N(int p);
}
Comment #2
Posted on May 16, 2011 by Grumpy CatI fixed this issue by changing one method 'Matches' in 'MethodCall' class (MethodCall.cs) from: public virtual bool Matches(ICallContext call) { if (condition != null && !condition()) { return false; }
var parameters = call.Method.GetParameters();
var args = new List<object>();
for (int i = 0; i < parameters.Length; i++)
{
if (!parameters[i].IsOutArgument())
{
args.Add(call.Arguments[i]);
}
}
if (argumentMatchers.Count == args.Count && this.IsEqualMethodOrOverride(call))
{
for (int i = 0; i < argumentMatchers.Count; i++)
{
if (!argumentMatchers[i].Matches(args[i]))
{
return false;
}
}
return true;
}
return false;
}
to: public virtual bool Matches(ICallContext call) { var parameters = call.Method.GetParameters(); var args = new List(); for (int i = 0; i < parameters.Length; i++) { if (!parameters[i].IsOutArgument()) { args.Add(call.Arguments[i]); } }
if (argumentMatchers.Count == args.Count && this.IsEqualMethodOrOverride(call))
{
for (int i = 0; i < argumentMatchers.Count; i++)
{
if (!argumentMatchers[i].Matches(args[i]))
{
return false;
}
}
return condition == null || condition(); // <<replacement>> should check condition only in case of all argumets are matched
}
return false;
}
The problem was in condition() implementation of MockSequence class which for first setup check increase sequence counter.
PS All tests are successfully passed
Comment #3
Posted on Feb 13, 2012 by Quick ElephantI also stumbled on this issue, the fix seems easy, so +1 !
Comment #4
Posted on Nov 14, 2012 by Grumpy LionAny news on this issue?
A poor man's approach to verifying the order in which mocks are called, is to maintain your own counter with callbacks, and Assert the value of the counter variable:
Comment #5
Posted on Nov 14, 2012 by Quick MonkeyPull request @ github.com/Moq/moq4 ?
Comment #6
Posted on Dec 27, 2012 by Helpful BearHi,
I have coded together a new feature proposal for sequential verification for Moq at: https://github.com/grzesiek-galezowski/moq4. This proposal includes sequential verification that works with loose mocks and also three types of sequence behaviors. The changes need some review (does it work properly? Is it needed? Is something missing?), so anybody reading this, please test this implementation and add comments to https://github.com/Moq/moq4/issues/21. The examples on how to use the proposed functionality can be found at: https://github.com/grzesiek-galezowski/moq4/blob/dev/UnitTests/VerifyInSequenceFixture.cs
Best regards, grzesiek gałęzowski
Comment #7
Posted on Jan 7, 2014 by Grumpy ElephantIs this STILL not working? A YEAR after a suggested solution was posted?
Status: New
Labels:
Type-Defect
Priority-Medium