我有一个由两个步骤组成的过程:
(步骤1)首先从远程方请求令牌;
(步骤2)第二,它使用令牌触发远程作业。
到目前为止我的解决方案是:
test1()(当然)测试(步骤1);
test2(),其中包含test1()的全部代码以及测试代码(步骤2)。
虽然解决方案的工作我不喜欢它,所以我正在寻找更好的东西。
答案 0 :(得分:1)
你说你有一个包含两个步骤的过程。正如您已经确定了这些不连续的步骤,您应该将它们封装到单独的方法中,例如
(注意:以下代码非常简单。如果您在问题中包含代码,这将有所帮助)
而不是:
void TriggerRemoteJob()
{
// Step 1 - Code to request a token from a remote party.
// Step 2 - Code to use the token to trigger a remote job.
}
你可以:
Token GetToken(string remotePartyId)
{
return RemoteParty.GetToken(remotePartyId);
}
int TriggerRemoteJob(Token token)
{
return RemoteJobManager.TriggerJob(token);
}
“RemoteParty”和“RemoteJobManager”都是可以使用依赖注入注入到类中的依赖项。
采用这种方法,您可以使用TDD开发“GetToken”和“TriggerJob”。使用TDD时,您应该模拟外部依赖项,并仅测试您正在开发的方法。因此,在测试“TriggerRemoteJob”时,您将 模拟 令牌。
在评论中你说:
“我想尽可能真实地测试这个过程。”
我建议您使用BDD方法进行开发(在StackOverflow上搜索BDD,这个主题有很多很棒的答案)。这种方法迫使您开发“从内到外”,在此处您将恢复使用TDD作为BDD流程的一部分。这种方法将运行解决方案中的所有层,以便您“尽可能真实地”测试流程,同时编写使用模拟的测试(通过TDD)。
答案 1 :(得分:0)
因为你要去to TDD a 2-steps process which requires input from a remote party
,所以你一定要嘲笑remote party
。
我建议您使用MOQ或NSubstitute作为模拟框架。
我看到没有必要编写两个测试,因为两个调用非常依赖。
我宁愿只编写一个测试来测试你的两步流程
[TestClass]
public class ClientTest
{
/// <summary>
/// This test can test only the fact of invocation only.
/// </summary>
[TestMethod]
public void DoSmth_RequestsTokenFromRemoteParty()
{
// act
target.DoSmth();
// assert
remotePartyMock.Verify(it => it.RequestTtoken());
}
/// <summary>
/// It is enough to have this test only.
/// It contains token setup and following verification of triggering job with correct tocken.
/// </summary>
[TestMethod]
public void DoSmth_RequestsTokenAndTriggersRemoteJob()
{
// arrange
var expectedTocken = Guid.NewGuid();
remotePartyMock.Setup(it => it.RequestTtoken()).Returns(expectedTocken);
// act
target.DoSmth();
// assert
remotePartyMock.Verify(it => it.TriggerRemoteJob(expectedTocken));
}
private Mock<IRemoteParty> remotePartyMock;
private Client target;
public void Init()
{
remotePartyMock = new Mock<IRemoteParty>();
target = new Client(remotePartyMock.Object);
}
}
#region Client & IRemoteParty
public class Client
{
private readonly IRemoteParty remoteParty;
/// <summary>
/// There is a constructor injection.
/// </summary>
public Client(IRemoteParty remoteParty)
{
this.remoteParty = remoteParty;
}
public void DoSmth()
{
var tocken = remoteParty.RequestTtoken();
remoteParty.TriggerRemoteJob(tocken);
}
}
public interface IRemoteParty
{
Guid RequestTtoken();
void TriggerRemoteJob(Guid token);
}
#endregion