文档

§测试您的应用程序

为您的应用程序编写测试可能是一个复杂的过程。Play 支持 JUnit 并提供助手和应用程序存根,使测试您的应用程序尽可能容易。

§概述

测试的位置在“test”文件夹中。在 test 文件夹中创建了两个示例测试文件,可用作模板。

您可以从 sbt 控制台运行测试。

Play 中的测试基于 sbt,完整的描述可在 测试文档 中找到。

§使用 JUnit

测试 Play 应用程序的默认方法是使用 JUnit

import static org.junit.Assert.*;

import org.junit.Test;

public class SimpleTest {

  @Test
  public void testSum() {
    int a = 1 + 1;
    assertEquals(2, a);
  }

  @Test
  public void testString() {
    String str = "Hello world";
    assertFalse(str.isEmpty());
  }
}

注意:每次运行 testtest-only 时都会分叉一个新进程。新进程使用默认的 JVM 设置。自定义设置可以添加到 build.sbt 中。例如

Test / javaOptions ++= Seq(
  "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9998",
  "-Xms512M",
  "-Xmx1536M",
  "-Xss1M"
)

§断言和匹配器

一些开发人员更喜欢以比 JUnit 断言更流畅的方式编写他们的断言。为了方便起见,包含了其他断言样式的流行库。

Hamcrest 匹配器

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;

import org.junit.Test;

public class HamcrestTest {

  @Test
  public void testString() {
    String str = "good";
    assertThat(str, allOf(equalTo("good"), startsWith("goo")));
  }
}

§模拟

模拟用于隔离针对外部依赖项的单元测试。例如,如果您的测试类依赖于外部数据访问类,您可以模拟它以提供受控数据并消除对外部数据资源的需求。

Mockito 库是一个流行的 Java 模拟框架。要在测试中使用它,请在您的 `build.sbt` 文件中添加对 `mockito-core` 工件的依赖项。例如

libraryDependencies += "org.mockito" % "mockito-core" % "2.10.0" % "test"

您可以在 这里 找到 `mockito-core` 的当前版本号。

使用 Mockito,您可以像这样模拟类或接口

import static org.mockito.Mockito.*;
// Create and train mock
List<String> mockedList = mock(List.class);
when(mockedList.get(0)).thenReturn("first");

// check value
assertEquals("first", mockedList.get(0));

// verify interaction
verify(mockedList).get(0);

§单元测试模型

假设我们有以下数据模型

public class User {
  private Integer id;
  private String name;

  public User(final Integer id, final String name) {
    this.id = id;
    this.name = name;
  }
}

public class Role {
  private String name;

  public Role(final String name) {
    this.name = name;
  }
}

一些数据访问库,例如 Ebean,允许您使用静态方法将数据访问逻辑直接放在模型类中。这可能会使模拟数据依赖项变得棘手。

一种常见的可测试性方法是将模型与数据库隔离,并尽可能地隔离逻辑,并将数据库访问抽象到存储库接口后面。

public interface UserRepository {
  public Set<Role> findUserRoles(User user);
}

public class UserRepositoryEbean implements UserRepository {
  @Override
  public Set<Role> findUserRoles(User user) {
    // Get roles from DB
     ...
  }
}

然后使用包含存储库的服务与您的模型进行交互

public class UserService {
  private final UserRepository userRepository;

  public UserService(final UserRepository userRepository) {
    this.userRepository = userRepository;
  }

  public boolean isAdmin(final User user) {
    final Set<Role> roles = userRepository.findUserRoles(user);
    for (Role role : roles) {
      if (role.name.equals("ADMIN")) return true;
    }
    return false;
  }
}

通过这种方式,可以通过模拟 `UserRepository` 依赖项来测试 `UserService.isAdmin` 方法

@Test
public void testIsAdmin() {

  // Create and train mock repository
  UserRepository repositoryMock = mock(UserRepository.class);
  Set<Role> roles = new HashSet<Role>();
  roles.add(new Role("ADMIN"));
  when(repositoryMock.findUserRoles(any(User.class))).thenReturn(roles);

  // Test Service
  UserService userService = new UserService(repositoryMock);
  User user = new User(1, "Johnny Utah");
  assertTrue(userService.isAdmin(user));
  verify(repositoryMock).findUserRoles(user);
}

§单元测试控制器

您可以使用 Play 的 测试助手 来测试您的控制器,以提取有用的属性。

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static play.mvc.Http.Status.OK;
import static play.test.Helpers.*;

import javaguide.tests.controllers.HomeController;
import org.junit.Test;
import play.mvc.Result;
import play.twirl.api.Content;

public class ControllerTest {

  @Test
  public void testIndex() {
    Result result = new HomeController().index();
    assertEquals(OK, result.status());
    assertEquals("text/html", result.contentType().get());
    assertEquals("utf-8", result.charset().get());
    assertTrue(contentAsString(result).contains("Welcome"));
  }

}

§单元测试视图模板

由于模板只是一个方法,您可以从测试中执行它并检查结果

@Test
public void renderTemplate() {
    Content html = views.html.index.render("Welcome to Play!");
  assertEquals("text/html", html.contentType());
  assertTrue(contentAsString(html).contains("Welcome to Play!"));
}

§使用 Messages 进行单元测试

如果您需要一个 `play.i18n.MessagesApi` 实例用于单元测试,可以使用 play.test.Helpers.stubMessagesApi() 来提供一个

@Test
public void renderMessages() {
  Langs langs = new Langs(new play.api.i18n.DefaultLangs());

  Map<String, String> messagesMap = Collections.singletonMap("foo", "bar");
  Map<String, Map<String, String>> langMap =
      Collections.singletonMap(Lang.defaultLang().code(), messagesMap);
  MessagesApi messagesApi = play.test.Helpers.stubMessagesApi(langMap, langs);

  Messages messages = messagesApi.preferred(langs.availables());
  assertEquals(messages.at("foo"), "bar");
}

下一步:编写功能测试


在此文档中发现错误?此页面的源代码可以在 这里 找到。在阅读 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?转到 我们的社区论坛 与社区开始对话。