Reputation: 716
Lets say I have a method A
public class ClassWithAMethod
{
public static void A(string email)
{
var b = SomeClass.StaticMethod();
var c = b.GetUser(x => x.Email == email);
if (c != null)
{
throw new Exception();
}
}
}
And I need to test a method Abc
, which calls method A
.
For example
public void Abc()
{
ClassWithAMethod.A("[email protected]");
}
So I need to mock object b
and setup method GetUser
but how can I do that?
Upvotes: 0
Views: 122
Reputation: 22759
As the adage goes: You can solve every problem with another level of indirection, except for the problem of too many levels of indirection Reference
By introducing a wrapper / adapter your solution become a bit more loosely coupled.
So, first let's introduce the following interface:
public interface IBFactory
{
B Create();
}
Let's create the wrapper:
public class BWrapper: IBFactory
{
public B Create()
{
return SomeClass.StaticMethod();
}
}
In case of C# 8 you can combine the previous two steps into one by relying on the default implementation in interface feature:
public interface IBFactory
{
public B Create()
{
return SomeClass.StaticMethod();
}
}
Now let's modify the ClassWithAMethod
class to rely on the IBFactory
:
public class ClassWithAMethod
{
private readonly IBFactory _bFactory;
public ClassWithAMethod(IBFactory bFactory)
{
this._bFactory = bFactory;
}
public static void A(string email)
{
var b = this._bFactory.Create();
var c = b.GetUser(x => x.Email == email);
if (c != null)
{
throw new Exception();
}
}
}
You can register the BWrapper
as the default implementation for IBFactory
in your DI container. Or if you are not using DI nor C# 8 then you can specify a parameterless ctor where you rely on BWrapper
. Please bear in mind that this approach is not advised. It is more like a last resort.
public class ClassWithAMethod
{
private readonly IBFactory _bFactory;
public ClassWithAMethod()
{
this._bFactory = new BWrapper();
}
public ClassWithAMethod(IBFactory bFactory)
{
this._bFactory = bFactory;
}
...
}
Now you can mock that dependency as well.
var bFactoryMock = new Mock<IBFactory>();
bFactoryMock.Setup(factory => factory.Create()).Returns(...);
var SUT = new ClassWithAMethod(bFactoryMock.Object);
Upvotes: 1
Reputation: 1449
Without modification, i don't think this is possible.
a slight modification and non breaking change could be to add an optional param bGetter
to get the b.
You can then create your own bGetter
in your unit test.
public class ClassWithAMethod
{
public static void A(string email, Func<B> bGetter = null)
{
var b = null == bGetter ? SomeClass.StaticMethod() : bGetter();
var c = b.GetUser(x => x.Email == email);
if (c != null)
{
throw new Exception();
}
}
}
Upvotes: 3