You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Playframework 2.6 [Java]:含@Inject的控制器测试方法求助

嘿,我来帮你解决Play Framework里测试带@Inject的控制器这个问题!其实核心就是处理依赖注入的测试场景,分单元测试和集成测试两种方式,我给你详细说下具体实现:

先明确前提

假设你的PersonController是这样的(带注入的依赖,比如PersonService):

import play.mvc.Controller;
import play.mvc.Result;
import javax.inject.Inject;

public class PersonController extends Controller {
    private final PersonService personService;

    // 通过@Inject注入依赖
    @Inject
    public PersonController(PersonService personService) {
        this.personService = personService;
    }

    // 要测试的createPerson方法
    public Result createPerson(String name, int age) {
        Person newPerson = new Person(name, age);
        personService.save(newPerson);
        return ok("Person created successfully");
    }
}

方式一:单元测试(隔离依赖)

单元测试的目标是只测控制器本身的逻辑,把依赖用Mock替代,避免依赖真实的数据库或服务。这里用Mockito来Mock依赖,配合Guice来注入Mock实例:

测试代码示例

import org.junit.Test;
import static org.mockito.Mockito.*;
import play.mvc.Result;
import static play.test.Helpers.*;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;

public class PersonControllerUnitTest {

    @Test
    public void testCreatePerson_ShouldReturnOkAndCallService() {
        // 1. Mock依赖的PersonService
        PersonService mockPersonService = mock(PersonService.class);

        // 2. 创建Guice模块,绑定Mock实例到PersonService接口
        Injector injector = Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(PersonService.class).toInstance(mockPersonService);
            }
        });

        // 3. 从Injector获取控制器实例(自动注入Mock依赖)
        PersonController controller = injector.getInstance(PersonController.class);

        // 4. 调用要测试的方法
        Result result = controller.createPerson("Alice", 30);

        // 5. 验证返回结果是否符合预期
        assertEquals(OK, result.status());
        assertEquals("Person created successfully", contentAsString(result));

        // 6. 验证Mock的服务是否被正确调用
        verify(mockPersonService).save(any(Person.class));
    }
}

方式二:集成测试(完整流程)

如果要测试从路由到控制器再到服务的完整流程,就用集成测试。Play提供了GuiceOneAppPerTest基类,帮你启动测试用的Application实例,自动处理依赖注入:

测试代码示例

import org.junit.Test;
import play.test.GuiceOneAppPerTest;
import play.mvc.Result;
import static play.test.Helpers.*;
import javax.inject.Inject;

public class PersonControllerIntegrationTest extends GuiceOneAppPerTest {

    // 自动注入真实的控制器实例(Play会帮你处理依赖注入)
    @Inject
    private PersonController personController;

    @Test
    public void testCreatePerson_DirectCall() {
        // 直接调用控制器方法测试
        Result result = personController.createPerson("Bob", 25);
        assertEquals(OK, result.status());
        assertEquals("Person created successfully", contentAsString(result));
    }

    @Test
    public void testCreatePerson_ViaRoute() {
        // 更贴近真实场景:模拟HTTP请求,通过路由访问控制器
        Result routeResult = route(app, 
            fakeRequest(POST, "/create-person")
                .withFormUrlEncodedBody("name", "Charlie", "age", "35")
        );
        assertEquals(OK, routeResult.status());
    }
}

必要的测试依赖

记得在build.sbt里添加测试相关的依赖,不然会报错:

libraryDependencies ++= Seq(
  guice,
  "org.scalatestplus.play" %% "scalatestplus-play" % "5.1.0" % Test,
  "org.mockito" % "mockito-core" % "5.6.0" % Test
)

简单总结下:单元测试适合快速验证控制器逻辑,隔离外部依赖;集成测试适合验证完整的请求流程,确保各个组件协同工作正常。根据你的需求选对应的方式就行!

内容的提问来源于stack exchange,提问作者MaVa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:12:08