我最近偶然发现了interesting concept这可能为我节省了大量的测试工作。 我不明白的是如何在运行时注入提供程序?
这个场景很简单:我在运行时使用我选择的模拟框架构建一个模拟对象,但我事先并不知道生成的类的名称,因为它是一个mock(所以我无法配置)它提前,不是我想)。
有没有人在单元测试中成功使用这种技术?
谢谢。
答案 0 :(得分:3)
该文章中描述的概念是在后台使用Ambient Context的Service Locator。
由于使用静态属性和使用服务定位器,这种模式对于单元测试非常不方便。为了能够运行验证使用此单例的代码的测试,您需要设置一个有效的服务定位器,并使用您关心使用测试的单例(可能是模拟实例)对其进行配置。
即使是文章给出的例子也已经受到这些问题的困扰,因为“你喜欢单身吗?”代码,很难测试:
if (DialogDisplayer.getDefault().yesOrNo(
"Do you like singletons?"
)) {
System.err.println("OK, thank you!");
} else {
System.err.println(
"Visit http://singletons.apidesign.org to"
+ " change your mind!"
);
}
更好的选择是使用构造函数注入来注入该单例(请原谅我的法语,但我不是本地Java发言人):
public class AskTheUserController
{
private DialogDisplayer dialogDisplayer;
private MessageDisplayer messageDisplayer;
public AskTheUserController(DialogDisplayer dialogDisplayer,
MessageDisplayer messageDisplayer)
{
this.dialogDisplayer = dialogDisplayer;
this.messageDisplayer = messageDisplayer;
}
public void AskTheUser()
{
if (this.dialogDisplayer.yesOrNo(
"Do you like singletons?"
)) {
this.messageDisplayer.display("OK, thank you!");
} else {
this.messageDisplayer.display(
"Visit http://singletons.apidesign.org to"
+ " change your mind!"
);
}
}
}
该代码中还有另一个“隐藏”依赖项:System.err.println
。它使用MessageDisplayer
接口进行抽象。这段代码有一些明显的优点:
您的测试可能如下所示:
@Test
public void AskTheUser_WhenUserSaysYes_WeThankHim()
{
// Arrange
bool answer = true;
MockMessageDisplayer message = new MockMessageDisplayer();
MockDialogDisplayer dialog = new MockDialogDisplayer(answer);
AskTheUserController controller =
new AskTheUserController(dialog, message);
// Act
controller.AskTheUser();
// Assert
Assert.AreEqual("OK, thank you!", message.displayedMessage);
}
@Test
public void AskTheUser_WhenUserSaysNo_WeLetHimChangeHisMind()
{
// Arrange
bool answer = true;
MockMessageDisplayer message = new MockMessageDisplayer();
MockDialogDisplayer dialog = new MockDialogDisplayer(answer);
AskTheUserController controller =
new AskTheUserController(dialog, message);
// Act
controller.AskTheUser();
// Assert
Assert.IsTrue(
message.displayedMessage.contains("change your mind"));
}
当您使用文章中所示的“可注射单身人士”模式时,您的测试代码将永远不会像上面的代码一样显示。
答案 1 :(得分:1)
单身人士没有任何问题,单身人士在任何软件中都是有用且必要的概念。问题是你不应该用静态字段和方法来实现它们。
我使用Guice注入我的单身人士,并且我不必在我的代码库中使用静态并在很长一段时间内进行测试。
以下是一些您可能会发现有用的链接,解释如何使用Guice实现可测试的单例: