Error CS0854 when you’re using Moq with optional parameters

Problem

Optional parameters aren’t optional when you’re using Moq.

When you’re setting up or verifying a method call on a mock object, and the method has an optional parameter that you didn’t specify a value for, you’ll get the following compiler error:

Error CS0854 – An expression tree may not contain a call or invocation that uses optional arguments

This strange error isn’t specific to Moq. It happens any time you’re trying to use optional parameters with an expression tree (System.Linq.Expressions). Moq uses expression tree parameters, which is why you’ll often run into this error when using Moq. For example, here’s the Moq Setup() method:

public ISetup<T> Setup(Expression<Action<T>> expression);
Code language: C# (cs)

To fix this error, you have to pass in values for any optional parameters in the method you’re mocking. I’ll show an example below.

Note: The IDE suggested fixes for this error don’t make sense and only increase the confusion about it.

Solution: You must specify a value for the optional parameter

Let’s say you want to mock the following repository interface:

public interface IRepository
{
	public void Save(bool inTransaction=false);
}
Code language: C# (cs)

The Save() method has an optional parameter. When you try to setup / verify the Save() method on the mock object, you’ll get the CS0854 error:

var mockRepo = new Mock<IRepository>();
var service = new Service(mockRepo.Object);

mockRepo.Setup(t => t.Save()).Throws(new Exception());

service.Save();

mockRepo.Verify(t => t.Save());
Code language: C# (cs)

To fix this, you have to pass in a value for the optional parameter in the calls to Save(), like this:

var mockRepo = new Mock<IRepository>();
var service = new Service(mockRepo.Object);

mockRepo.Setup(t => t.Save(true)).Throws(new Exception());

service.Save();

mockRepo.Verify(t => t.Save(It.IsAny<bool>()));
Code language: C# (cs)

Notice that you can pass in a hardcoded value (like Save(true)), or you can pass in It.IsAny() if it the specific value used for the parameter doesn’t matter for your test.

Leave a Comment