使用模拟对象对Play控制器进行单元测试

8

标题基本上已经说明了一切。我想设置一个传统的JUnit测试来模拟控制器的依赖关系,并对操作运行测试。

我发现我可以这样实现我的目标:

public class AccountsControllerTest {
    private controllers.Accounts accountsController;

    @Test
    public void test() {
        running(fakeApplication(), new Runnable() {
            public void run() {
                accountsController = new controllers.Accounts();
                accountsController.setAccountsWorkflow(mock(workflow.Accounts.class));
            }
        });
    }
}

这里的明显问题是,我正在测试方法中实例化我的被测类并注入模拟依赖项,而我应该在 setup() 方法中这样做。如果我要以传统方式测试我的控制器,那么 setup() 方法似乎就没用了。
当然,我可以按照 Play 推荐的方式进行控制器测试,但我的应用程序依赖于外部 SOAP web 服务,因此我需要单元测试来显示我们的代码在他们的服务器关闭时工作。
那么,在使用模拟的情况下,如何最好地单元测试 Play 控制器,并仍然利用 setup()teardown() 方法呢? 编辑 我意识到我在这里假设一些知识,所以对于那些不知道的人来说,单元测试中的控制器实例化必须包含在一个 running() 函数中,否则 Play!会抛出运行时异常,提示没有启动应用程序。

http://www.joergviola.de/blog/2012/06/04/page-driven-functional-tests-for-play-2-dot-0/是测试的一个好方式,但仍然存在模拟问题。你可以尝试在没有fakeApplication的情况下运行测试。参见https://dev59.com/JmPVa4cB1Zd3GeqP4EjW - niels
https://dev59.com/ZmLVa4cB1Zd3GeqPwG7n#10114621 - Blake Pettersson
谢谢你的示例。你是如何在running函数之外实例化控制器的?这个限制阻止了我利用JUnit的setup方法,以便我不必在每个测试方法中设置模拟对象。你的示例并没有真正展示这一点。 - Samo
@Samo,你有什么进展吗?我想要验证从控制器返回的视图,但不是通过检查HTML内容。我想要验证传递的正确视图名称。 - Ankit Dhingra
我不知道 Result 类型的数据是否可用于 Play 框架。看起来似乎不行。您可以使用我问题中展示的格式来使用 mock 单元测试控制器,但您将无法使用 setup() 方法,因此您需要在测试方法之间重复大量模拟。 - Samo
1个回答

1

您可以使用Mockito和Play的FakeApplication,并设置静态Http.Context变量来实现此目的。

这样,您就可以像所有其他JUnit测试一样编写测试。

例如:

...
import static play.test.Helpers.status;
import play.test.FakeApplication;
import play.test.Helpers;
import play.mvc.Http;
import play.mvc.Result;
...

@RunWith(MockitoJUnitRunner.class)
public class ApplicationTest {

  public static FakeApplication app;

  @Mock
  private Http.Request request;

  @BeforeClass
  public static void startApp() {
      app = Helpers.fakeApplication();
      Helpers.start(app);

  }

  @Before
  public void setUp() throws Exception {
      Map<String, String> flashData = Collections.emptyMap();
      Http.Context context = new Http.Context(request, flashData, flashData);
      Http.Context.current.set(context);
  }

  @Test
  public void testIndex() {
      final Result result = Application.index();
      assertEquals(play.mvc.Http.Status.OK, status(result));
  }

  @AfterClass
  public static void stopApp() {
      Helpers.stop(app);
  }

我不知道你可以像那样设置当前的 Http.Context -- 那很酷,谢谢。 - duma
我发现通过设置 Http.Context.current.set(context);,我的后续依赖于 Application 的测试失败了。因此,你必须在 @AfterClass 中将上下文设置回其原始状态。 - Richard Lewan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接