在单元测试中跳过内部方法调用
Skip inner method calls in unit testing
比方说,我有方法 A、B、C 和 D。
public bool A (int foo)
{
bool result = false;
if (foo > 0)
result = B();
else result = C();
D(foo);
return result;
}
我想为A写一个单元测试,调用B或C,但想跳过D调用(因为它是一个使用外部服务的方法)。是否可以使用某些属性跳过 D 调用?或者模拟 D,用一些虚假服务代替它?
这凸显了设计代码使其可进行单元测试的重要性。依赖注入在这方面非常有用。然后,您可以在单元测试时模拟依赖项。例如,您可能有一个可以通过接口 ICommunications 访问的通信层。然后,您的 class 将在其构造函数中引用一个 ICommunications 对象:
public class TestableClass
{
private ICommunications _comms;
public TestableClass(ICommunications comms)
{
_comms = comms;
}
public bool FunctionToTest()
{
//do something testable
_comms.SomeFunction();//mocked object in unit tests
//do something else testable
}
}
然后只需创建一个模拟版本的通讯并在测试期间将其传入即可。您还可以将代码添加到您的模拟 class 以模拟某些测试条件 - 例如,对于接收一些无效数据的通信层。
您需要使具有方法 A()
的 class 依赖于方法 D()
使用的外部服务。您可以使用任何 DI 模式来执行此操作,尽管构造函数注入可能是最好的起点。
一旦您处于这种情况,D()
所依赖的外部服务就可以被伪造并注入到 class 中。测试现在由您通过假货的行为进行控制。
类似于:
class Thing
{
private IExternalService _externalService;
public Thing(IExternalService externalService)
{
_externalService = externalService;
}
public void A() { ... }
public void D(string foo)
{
_externalService.DoSomeStuff();
}
}
然后:
[Fact]
public void TestThisOut()
{
var fakeExternalService = new MockFramework.CreateMock();
fakeExternalService
.ShouldDoSomethingWhen(s => s.DoSomeStuff())
.IsCalled();
var testThing = new Thing(fakeExternalService);
testThing.A();
Assert.That(testThing, Did.Some.Thing());
}
你需要mock方法D,我写了一个例子,使用Typemock Isolator,你看看:
class Methods
{
public bool A(int foo)
{
bool result = false;
if (foo > 0)
result = B();
else
result = C();
D(foo);
return result;
}
public void D(int foo) {throw new NotImplementedException();}
public bool C() { return false;}
public bool B() { return true;}
}
测试:
[TestMethod, Isolated]
public void TestIgnoreD()
{
//Arrange
Methods methods = new Methods();
Isolate.WhenCalled(() => methods.D(0)).IgnoreCall();
//Act
bool result = methods.A(1);
//Assert
Assert.IsTrue(result);
}
我将它们全部放在一个 class 中只是因为我不知道您的代码中发生了什么。无论如何,Isolator 相当灵活,因为它允许从几乎所有地方模拟几乎所有东西。
比方说,我有方法 A、B、C 和 D。
public bool A (int foo)
{
bool result = false;
if (foo > 0)
result = B();
else result = C();
D(foo);
return result;
}
我想为A写一个单元测试,调用B或C,但想跳过D调用(因为它是一个使用外部服务的方法)。是否可以使用某些属性跳过 D 调用?或者模拟 D,用一些虚假服务代替它?
这凸显了设计代码使其可进行单元测试的重要性。依赖注入在这方面非常有用。然后,您可以在单元测试时模拟依赖项。例如,您可能有一个可以通过接口 ICommunications 访问的通信层。然后,您的 class 将在其构造函数中引用一个 ICommunications 对象:
public class TestableClass
{
private ICommunications _comms;
public TestableClass(ICommunications comms)
{
_comms = comms;
}
public bool FunctionToTest()
{
//do something testable
_comms.SomeFunction();//mocked object in unit tests
//do something else testable
}
}
然后只需创建一个模拟版本的通讯并在测试期间将其传入即可。您还可以将代码添加到您的模拟 class 以模拟某些测试条件 - 例如,对于接收一些无效数据的通信层。
您需要使具有方法 A()
的 class 依赖于方法 D()
使用的外部服务。您可以使用任何 DI 模式来执行此操作,尽管构造函数注入可能是最好的起点。
一旦您处于这种情况,D()
所依赖的外部服务就可以被伪造并注入到 class 中。测试现在由您通过假货的行为进行控制。
类似于:
class Thing
{
private IExternalService _externalService;
public Thing(IExternalService externalService)
{
_externalService = externalService;
}
public void A() { ... }
public void D(string foo)
{
_externalService.DoSomeStuff();
}
}
然后:
[Fact]
public void TestThisOut()
{
var fakeExternalService = new MockFramework.CreateMock();
fakeExternalService
.ShouldDoSomethingWhen(s => s.DoSomeStuff())
.IsCalled();
var testThing = new Thing(fakeExternalService);
testThing.A();
Assert.That(testThing, Did.Some.Thing());
}
你需要mock方法D,我写了一个例子,使用Typemock Isolator,你看看:
class Methods
{
public bool A(int foo)
{
bool result = false;
if (foo > 0)
result = B();
else
result = C();
D(foo);
return result;
}
public void D(int foo) {throw new NotImplementedException();}
public bool C() { return false;}
public bool B() { return true;}
}
测试:
[TestMethod, Isolated]
public void TestIgnoreD()
{
//Arrange
Methods methods = new Methods();
Isolate.WhenCalled(() => methods.D(0)).IgnoreCall();
//Act
bool result = methods.A(1);
//Assert
Assert.IsTrue(result);
}
我将它们全部放在一个 class 中只是因为我不知道您的代码中发生了什么。无论如何,Isolator 相当灵活,因为它允许从几乎所有地方模拟几乎所有东西。