春季@mockbean不注入黄瓜



我正在实现使用AgentRestClient bean从外部系统获取一些数据的SchedulerService。看起来像这样:

@Service
public class SchedulerService {
  @Inject
  private AgentRestClient agentRestClient;
  public String updateStatus(String uuid) {
    String status = agentRestClient.get(uuid);
    ...
  }
  ...
}

要测试此服务,我正在使用Cucumber,同时我尝试使用Spring Boot的@MockBean注释来模拟AgentRestClient的行为,如下:

import cucumber.api.CucumberOptions;
import cucumber.api.java.Before;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = CentralApp.class)
@CucumberOptions(glue = {"com.company.project.cucumber.stepdefs", "cucumber.api.spring"})
public class RefreshActiveJobsStepDefs {
  @MockBean
  private AgentRestClient agentRestClient;
  @Inject
  private SchedulerService schedulerService;
  @Before
  public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
    given(agentRestClient.get(anyString())).willReturn("FINISHED");//agentRestClient is always null here
  }
  //Skipping the actual Given-When-Then Cucumber steps...
}

当我尝试运行任何黄瓜方案时,agentRestClient从未被模拟/注入。setUp()方法在NPE中失败:

java.lang.NullPointerException
  at com.company.project.cucumber.stepdefs.scheduler.RefreshActiveJobsStepDefs.setUp(RefreshActiveJobsStepDefs.java:38)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:498)
  at cucumber.runtime.Utils$1.call(Utils.java:37)
  at cucumber.runtime.Timeout.timeout(Timeout.java:13)
  at cucumber.runtime.Utils.invoke(Utils.java:31)
  at cucumber.runtime.java.JavaHookDefinition.execute(JavaHookDefinition.java:60)
  at cucumber.runtime.Runtime.runHookIfTagsMatch(Runtime.java:223)
  at cucumber.runtime.Runtime.runHooks(Runtime.java:211)
  at cucumber.runtime.Runtime.runBeforeHooks(Runtime.java:201)
  at cucumber.runtime.model.CucumberScenario.run(CucumberScenario.java:40)
  at cucumber.runtime.model.CucumberFeature.run(CucumberFeature.java:165)
  at cucumber.runtime.Runtime.run(Runtime.java:121)
  at cucumber.api.cli.Main.run(Main.java:36)
  at cucumber.api.cli.Main.main(Main.java:18)

要到达这一点,我遵循以下2个资源,但仍然没有运气才能正常工作:

  • https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-boot-1-4
  • http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/boot/test/mock/mockito/mockito/mockbean.html

罪魁祸首似乎是黄瓜整合到弹簧中,因为当我使用普通的junit @Test方法尝试相同的方法时,嘲笑如预期的。

所以你能告诉我我错过或误解的黄瓜或春季配置吗?

谢谢bogdan

@3WJ的方法对我有用。就我而言,bean可选地注入控制器。在这种情况下,@mockbean将行不通,我想原因是bean并不难引用。添加一个额外的注释@Autowired以使bean难以引用,然后弹簧将初始化bean。

@RestController
public class MyController {
    public MyController(@Autowired(required = false) IMyService myService) {
        this.myService = myService;
    }
    @GetMapping("/the/path")
    public ResponseEntity<String> getData() {
        if(this.myService==null){
            //Throw service unavaillable exception
        }
        String data = this.myService.getData();
        return new ResponseEntity<>(data, HttpStatus.OK);
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class MyControllerIT {
    @Value("${local.server.port}")
    private int port;
    private RestTemplate restTemplate;
    @Autowired
    @MockBean
    private IMyService myService 
    @Test
    public void testQuery() throws Exception {
        // restTemplate to call rest API....
    }
}

好的,所以我发现@MockBean注释被忽略了,因为我用黄瓜运行了测试,而不是通过Spring Boot运行它们。du ...

所以我用 @MockBean替换了 CC_9,然后手动将模拟的人注入我的服务层。

所以我的测试看起来像这样:

@SpringBootTest(classes = CentralApp.class)
@ContextConfiguration
public class RefreshActiveJobsStepDefs {
  @Inject
  private SchedulerService schedulerService;
  @Mock
  private AgentRestClient agentRestClient;
  @Before
  public void setup() throws Exception {
   MockitoAnnotations.initMocks(this);
   given(agentRestClient.get(anyString())).willReturn("FINISHED");
   schedulerService.setAgentRestClient(agentRestClient);
  }
  //Skipping the actual Given-When-Then Cucumber steps...
}

您可以看到,我还删除了@CucumberOptions(glue=...)注释,现在我确保通过跑步者将其传递,而对于CLI来说,它将通过使用--glue选项。

我希望这会有所帮助。

我在2023年遇到了这个问题,并在GitHub问题中的这一评论

中设法解决了该问题

@cucumbercontextconfiguration注释的类传递给Springs testContextManager,并且经过同一处理的类别将在Junit中。因此,这应该导致使用模拟的MyService Bean创建的应用程序上下文。

换句话说,您需要将@MockBean声明移至@CucumberContextConfiguration类,然后将其注入步骤定义类(例如使用@Autowired)。

这是对我有用的代码:

@SpringBootTest
@CucumberContextConfiguration
@RunWith(Cucumber.class)
@CucumberOptions(
        plugin = {"pretty"},
        glue = "xxx",
        features = "classpath:xxx"
)
public class AcceptanceTestSuite {
    @MockBean MyMock mock;
}

,然后

public class ScenarioStepDefinitions {
    @Autowired MyMock mock;
    // ... steps
}

@mockbean不忽略,bean被模拟但没有注入,因此您可以通过@Inject注入它,这对我来说很好:

@Inject
@MockBean
private AgentRestClient agentRestClient;

相关内容

  • 没有找到相关文章

最新更新