Reputation: 3
I am new to trying to mock things in unit tests...
Example Code simplified for posting:
namespace MockInvestigate.Monitor
{
internal interface IAgentRepo
{
Dictionary<string, string> GetAgentAppSettings(string moduleName);
}
public class AgentRepo : IAgentRepo
{
public virtual Dictionary<string, string> GetAgentAppSettings(string moduleName)
{
return new Dictionary<string, string> { { "real", "data" } };
}
}
}
This is the method I want to unit test - but override the call to GetAgentAppSettings
namespace MockInvestigate
{
public class Class1
{
public static bool IsInitialized(string taskName)
{
AgentRepo ar = new AgentRepo();
var arReturn = ar.GetAgentAppSettings(taskName);
return arReturn.ContainsKey("real");
}
}
}
The unit test - trying to mock the call to 'GetAgentAppSettings'
[TestMethod]
public void TestMethod1()
{
var repo = Substitute.ForPartsOf<AgentRepo>();
var appReturn = new Dictionary<string, string> { { "bogus", "bogus2" } };
repo.GetAgentAppSettings("somevalue").ReturnsForAnyArgs(appReturn);
bool retValue = Class1.IsInitialized("somevalue");
Assert.IsFalse(retValue);
}
When my test is run, the real GetAgentAppSettings
is called, returning "real", "data" and not the bogus data I want.
I have tried .When(...).DoNotCallBase()
.
Can my test be modified to work? Does the underlying code need to change to work?
Any help would be appreciated.
Upvotes: 0
Views: 668
Reputation: 3513
After creating the substitute repo
, you have to inject it inside Class1
.
In your code, however, you are creating the AgentRepo
inside the IsInitialized
method, thus it's not using the substitute you created in the test method.
You have to inject the substitute by constructor injection, property injection or method injection.
As the name suggests, constructor injection is when you inject the dependency from the constructor. Since the method IsInitialized
is static, that's not an option.
Likewise, property injection uses properties to inject the dependencies. You could create a static property, usually you'd stay away from it though.
It'd always use the same instance for every thread, hence you'd have to guarantee that the AgentRepo
is thread-safe.
As last resort, you can use the method injection. You'd get the AgentRepo
instance as a method argument and let the caller be responsible for creating it.
Since this is a small repro, I can't tell you what's the best way to deal with it. What I do know is that the AgentRepo
must be injected into Class1
somehow.
Upvotes: 1