使用 mock 对 Play 控制器进行单元测试

Posted

技术标签:

【中文标题】使用 mock 对 Play 控制器进行单元测试【英文标题】:Unit testing a Play controller using mocks 【发布时间】:2012-06-20 18:51:47 【问题描述】:

标题几乎说明了一切。我想设置一个传统的 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() 方法似乎没用。

当然,我可以测试控制器 the way Play recommends,但我的应用程序依赖于外部 SOAP Web 服务,因此我需要进行单元测试以表明我们的代码在其服务器关闭时可以正常工作。

那么,在利用 setup()teardown() 方法的同时使用模拟对 Play 控制器进行单元测试的最佳方法是什么?

编辑

我意识到我在这里假设了一些知识,所以对于那些不知道的人,单元测试中的控制器实例必须包含在 running() 函数或 Play!将抛出一个运行时异常,说明尚未启动任何应用程序。

【问题讨论】:

joergviola.de/blog/2012/06/04/… 也是一种很好的测试方式,但仍然存在模拟问题。您可以尝试在没有 fakeApplication 的情况下运行测试。见***.com/questions/10381354/… ***.com/a/10114621/89509 感谢您的示例。你是如何在running 函数之外实例化控制器的?这个约束使我无法利用 JUnit 的 setup 方法,因此我不必在每个测试方法上设置模拟。你的例子并没有真正证明这一点。 @Samo 运气好吗?我希望能够验证从控制器返回的视图,而不是通过检查 html 内容。我想验证是否传递了正确的视图名称。 我不知道这些数据是否适用于 Play 的 Result 类型。似乎不是。您可以使用我的问题中显示的格式使用模拟对您的控制器进行单元测试,您将无法使用您的 setup() 方法,因此您将在测试方法之间重复大量模拟。 【参考方案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 —— 这很酷;谢谢。 我发现通过设置Http.Context.current.set(context);,我后续依赖Application的测试失败了。因此,您必须在 @AfterClass 中将上下文设置回其原始状态。

以上是关于使用 mock 对 Play 控制器进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

使用 Mock 对 Laravel 5 Mail 进行单元测试

如何用mockito+spring进行单元测试

6.3 利用Go语言接口进行Mock单元测试

Play 2.2:使用 Play Caching (Scala) 对代码进行单元测试时出现问题

快速入门JAVA单元测试——mock

快速入门JAVA单元测试——mock