§测试您的应用程序
为您的应用程序编写测试可能是一个复杂的过程。Play 支持 JUnit 并提供助手和应用程序存根,使测试您的应用程序尽可能容易。
§概述
测试的位置在“test”文件夹中。在 test 文件夹中创建了两个示例测试文件,可用作模板。
您可以从 sbt 控制台运行测试。
- 要运行所有测试,请运行
test
。 - 要仅运行一个测试类,请运行
testOnly
,后跟类名,例如testOnly my.namespace.MyTest
。 - 要仅运行失败的测试,请运行
testQuick
。 - 要持续运行测试,请运行一个前面带有波浪号的命令,例如
~testQuick
。 - 要在控制台中访问测试助手,例如
FakeApplication
,请运行Test/console
。
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());
}
}
注意:每次运行
test
或test-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");
}
下一步:编写功能测试
在此文档中发现错误?此页面的源代码可以在 这里 找到。在阅读 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?转到 我们的社区论坛 与社区开始对话。