Reputation: 1180
How can I unit test DoWork
method?
public class SomeClass {
private readonly IClass1 class1;
private readonly Class2 class2;
// IClass1 and Class2 are injected in ctor
public string DoWork() {
// do some work
if(this.class2.Method2(() => this.class1.Method1())) {
return "done!";
}
// other work
}
}
public interface IClass1 {
void Method1();
}
public class Class2 {
public virtual bool Method2(Action action) {
// return true or false
}
}
Upvotes: 1
Views: 503
Reputation: 4114
From your code above I see that the injected IClass1 is used just to pass as parameter in injected class2. This is code smell!! The main class SomeClass should not know nothing about Class1. So I suggest to refactor your code in a way that Class2 will know about Class1 look at the code
public class SomeClass {
private readonly IClass2 class2;
public SomeClass(IClass2 class2)
{
this.class2 = class2;
}
// class1 and class2 are injected in ctor
public string DoWork() {
// do some work
if(this.class2.Method2()) {
return "done!";
}
// other work
return string.Empty;
}
}
public interface IClass1 {
void Method1();
}
public interface IClass2
{
bool Method2();
}
public class Class2 : IClass2
{
private IClass1 class1;
public Class2(IClass1 class1)
{
this.class1 = class1;
}
public virtual bool Method2() {
// return true or false
class1.Method1();
return true;
}
}
And then you can easy test it.
[Test]
public void WhenMethod2ReturnTrue_ThenDoWork_ShouldReturn_Done()
{
Mock<IClass2> class2 = new Mock<IClass2>();
SomeClass someClass = new SomeClass(class2.Object);
class2.Setup(x => x.Method2()).Returns(true);
var doWork = someClass.DoWork();
Assert.That(doWork,Is.EqualTo("done!"));
}
[Test]
public void WhenMethod2ReturnFalse_ThenDoWork_ShouldReturn_Empty()
{
Mock<IClass2> class2 = new Mock<IClass2>();
SomeClass someClass = new SomeClass(class2.Object);
class2.Setup(x => x.Method2()).Returns(false);
var doWork = someClass.DoWork();
Assert.That(doWork,Is.Empty);
}
I've used Moq library for Mocking interfaces
Upvotes: 1
Reputation: 247531
The following example uses Moq and FluentAssertions to test the SomeClass.DoWork
test case that involves Class2
invoking a member Method2
that takes an action that invokes IClass1.Method1
[TestClass]
public class SomeClassTests {
[TestMethod]
public void DoWork_Should_Be_Done() {
//Arrange
IClass1 class1 = Mock.Of<IClass1>();
Mock<Class2> class2 = new Mock<Class2>();
class2.Setup(_ => _.Method2(It.IsAny<Action>()))
.Returns(true)
.Callback((Action passedAction) => passedAction?.Invoke());
SomeClass subject = new SomeClass(class1, class2.Object);
string expected = "done!";
//Act
var actual = subject.DoWork();
//Assert
actual.Should().Be(expected); //actual == expected
Mock.Get(class1).Verify(_ => _.Method1(), Times.Once); //was action invoked
}
}
Ideally Class2
dependency sould be abstracted behind an interface
public interface IClass2 {
bool Method2(Action action);
}
public class Class2 : IClass2 {
//...
}
but that is outside of the scope of the original question.
The above test mocks the dependencies and their expected behavior. Variations of that test can be done to cover alternative scenarios that would allow for the complete coverage of that method.
Upvotes: 1