Reputation: 45
I know that I can new up an object and pass it in but I'm trying to match the syntax and patterns since the value is never actually used.
Implementation:
public interface IDemoProvider
{
string GetStringById(int? id);
}
public interface IDemoService
{
bool Validate(ServiceRequest request);
}
public class ServiceRequest
{
public string foo { get; set; }
public int? bar { get; set; }
}
public class SomeDemoProvider : IDemoProvider
{
public virtual string GetStringById(int? id)
{
if (id != null)
return "success";
else
return "else";
}
}
public class BaseDemoService : IDemoService
{
public IDemoProvider Provider { get; set; }
public virtual bool Validate(ServiceRequest request)
{
if (request.bar == null)
return false;
return true;
}
}
public class SomeDemoService : BaseDemoService
{
public SomeDemoService(IDemoProvider provider)
{
Provider = provider;
}
public virtual string Post(ServiceRequest request)
{
if (!Validate(request))
throw new Exception("Invalid Request");
return Provider.GetStringById(request.bar);
}
}
Test Code:
[TestFixture]
public class ProgramTests
{
[Test]
public void SomeDemoServiceTest()
{
var mockProvider = new Mock<IDemoProvider>();
mockProvider.Setup(p => p.GetStringById(It.IsAny<int?>())).Returns(() => "success");
object[] args = { mockProvider.Object };
var mockService = new Mock<SomeDemoService>(args) {CallBase = true};
mockService.Setup(s => s.Validate(It.IsAny<ServiceRequest>())).Returns(true);
string result = mockService.Object.Post(It.IsAny<ServiceRequest>());
Assert.AreEqual("success", result);
}
}
Issue
This results in a NullReferenceException
which makes sense since it's trying to resolve request.Id
while running which is null at the request level.
However, if I replace the parameter with null
, it works fine:
return Provider.GetStringById(null);
My question here is whether there's some way to make the interceptor recognize before evaluating the expression that it should just return the value instead of trying to evaluate the expression.
I could mock out the rest of the request object but it seems silly since the values are never used according to the test. The real question here is whether I should be writing the code or the test differently to avoid this scenario or if I'm over complicating an issue with a simple workaround.
Upvotes: 1
Views: 12771
Reputation: 247333
You are testing it wrong.
If you are trying to exercise the method under test then this line...
string result = mockService.Object.Post(It.IsAny<ServiceRequest>());
is being used incorrectly. You would use It.IsAny<ServiceRequest>()
as part of the setup. In the case of how you are trying to use it, it will result in null
in the Validate
method
request.bar == null
because the It.IsAny
expression is not actually passing anything into the method.
Read up on how to use Moq via the Moq Quickstart to get a better understanding of how to use it when testing.
Rewrite the test as
public void SomeDemoServiceTest() {
//Arrange
var mockProvider = new Mock<IDemoProvider>();
mockProvider.Setup(p => p.GetStringById(It.IsAny<int?>())).Returns(() => "success");
var mockService = new Mock<SomeDemoService>(mockProvider.Object) { CallBase = true };
mockService.Setup(s => s.Validate(It.IsAny<ServiceRequest>())).Returns(true);
var request = new ServiceRequest();
//Act
var result = mockService.Object.Post(request);
//Assert
Assert.AreEqual("success", result);
}
And the test should pass.
Upvotes: 2