Spring 中的服务未使用 Junit 设置值

发布于 2025-01-18 18:11:24 字数 1152 浏览 0 评论 0原文

我正在使用 Junit 测试我的服务,但结果不是预期的。 当我保存实体时,返回日期未在服务中设置。

测试:

@Test
@DisplayName("Should set determined time for return date")
public void shouldSetReturnDate() {

    ClientDTORequest dto = createNewDTOClient();
    Client client = createNewClient();

    Mockito.when(clientRepository.save(Mockito.any())).thenReturn(client);
    Client saved = clientService.save(dto);

    Assertions.assertEquals(dateTimeNow.plusMinutes(30), saved.getReturnDate());
}

我的createNewClient():

private Client createNewClient() {
    //the null param is the return date
    return new Client(1L, "name", null);
}

我的服务:

    public Client save(ClientDTORequest dto) {

        Client client = mapper.map(dto, Client.class);
        client.setReturnDate(dateTimeNow.plusMinutes(30));
        Client savedClient = clientRepository.save(client);

        return savedClient;
    }

当测试结果:

org.opentest4j.AssertionFailedError: 
Expected :2022-04-04T01:17:25.715895900
Actual   :null

结果没有被服务传递给mock时,这是我的镜头,但我不知道为什么。

谢谢!

Im testing my service with Junit but the result is not the expected.
When i save my entity, the return date is not setted in service.

Test:

@Test
@DisplayName("Should set determined time for return date")
public void shouldSetReturnDate() {

    ClientDTORequest dto = createNewDTOClient();
    Client client = createNewClient();

    Mockito.when(clientRepository.save(Mockito.any())).thenReturn(client);
    Client saved = clientService.save(dto);

    Assertions.assertEquals(dateTimeNow.plusMinutes(30), saved.getReturnDate());
}

My createNewClient():

private Client createNewClient() {
    //the null param is the return date
    return new Client(1L, "name", null);
}

My service:

    public Client save(ClientDTORequest dto) {

        Client client = mapper.map(dto, Client.class);
        client.setReturnDate(dateTimeNow.plusMinutes(30));
        Client savedClient = clientRepository.save(client);

        return savedClient;
    }

And when the test result:

org.opentest4j.AssertionFailedError: 
Expected :2022-04-04T01:17:25.715895900
Actual   :null

The result is not passed by the service to mock, this is my shot, but i dont know why.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

葬花如无物 2025-01-25 18:11:24

问题是您将其与“现在”相结合,因此该服务在运行时始终将有时间。
随着时间的推移,最好的工作方式之一是建模概念<代​​码>时钟或timeProvider并将其注入服务。然后,您可以模拟它以断言测试中的时间。

class Clock {
    LocalDateTime now() {
        return LocalDateTime.now().plusMinutes(30); // <-- as you needs
    }
}

class Service {

    private Clock clock;

    Service(Clock clock) {
        this.clock = clock;
    }

    void save(MyEntity entity) {
        entity.setCreatedDateTime(clock.now());
        //repositoty.save(entity);
    }
}

@Getter
class MyEntity {
    private LocalDateTime createdDateTime;

    public void setCreatedDateTime(LocalDateTime createdDateTime) {
        //assing it to a field
        this.createdDateTime = createdDateTime;
    }
}

class ServiceTest {

    @Mock
    private Clock clock;

    private Service service;

    @Test
    void testSave() {
        LocalDateTime fixedDateTimeNow = LocalDateTime.of(2022, 4, 3, 18, 0, 0);
        Mockito.when(clock.now()).thenReturn(fixedDateTimeNow);

        MyEntity entity = new MyEntity();
        service.save(entity);

        Assertions.assertEquals(fixedDateTimeNow, entity.getCreatedDateTime());
    }
}

注意:请注意在您的服务中保持状态,以免线程安全。因此,当“同时”进行多个服务电话时,您最终会出现并发问题。

The problem is you're coupled to "now", so the service always will have the time at the moment it runs.
One of the best ways of work with time is by modeling the concept Clock or TimeProvider and injecting it to the Service. Then you can mock it to assert the time in the test.

class Clock {
    LocalDateTime now() {
        return LocalDateTime.now().plusMinutes(30); // <-- as you needs
    }
}

class Service {

    private Clock clock;

    Service(Clock clock) {
        this.clock = clock;
    }

    void save(MyEntity entity) {
        entity.setCreatedDateTime(clock.now());
        //repositoty.save(entity);
    }
}

@Getter
class MyEntity {
    private LocalDateTime createdDateTime;

    public void setCreatedDateTime(LocalDateTime createdDateTime) {
        //assing it to a field
        this.createdDateTime = createdDateTime;
    }
}

class ServiceTest {

    @Mock
    private Clock clock;

    private Service service;

    @Test
    void testSave() {
        LocalDateTime fixedDateTimeNow = LocalDateTime.of(2022, 4, 3, 18, 0, 0);
        Mockito.when(clock.now()).thenReturn(fixedDateTimeNow);

        MyEntity entity = new MyEntity();
        service.save(entity);

        Assertions.assertEquals(fixedDateTimeNow, entity.getCreatedDateTime());
    }
}

Note: Be careful about holding state in your service, so it's not thread safe. So, you'll end up with concurrency problems when multiple calls to service occurs "at the same time".

饮惑 2025-01-25 18:11:24

如果您使用 @Autowired 注入 clientRepository 那么它不会模拟。尝试@SpyBean
(@Autowired ClientRepository clientRepository 不会模拟;@SpyBean ClientRepository clientRepository 应该模拟)

If you injected your clientRepository with @Autowired then it won't mock. Try @SpyBean
(@Autowired ClientRepository clientRepository wouldn't mock; @SpyBean ClientRepository clientRepository should mock)

七堇年 2025-01-25 18:11:24

经过几个小时的测试,我发现了问题:

我的服务正在更改数据,但我的模拟 :

Mockito.when(clientRepository.save(Mockito.any())).thenReturn(client); <-- mock overridden the changed data from service
Client saved = clientService.save(dto);

我找到了参数captor ,我可以从方法中获取对象致电:

声明绑架者:

@Captor
ArgumentCaptor<Client> clientCaptor;

使用测试方法:

Mockito.when(clientRepository.save(clientCaptor.capture())).thenReturn(client); //<-- capturing the result
clientService.save(dto);
Client saved = clientCaptor.getValue() //getting object

Assertions.assertEquals(dto.getReturnDate().plusMinutes(30), saved.getReturnDate()); //assertion

After some hours of testing i found the problem:

My service was changing data, but was overridden by my mock:

Mockito.when(clientRepository.save(Mockito.any())).thenReturn(client); <-- mock overridden the changed data from service
Client saved = clientService.save(dto);

So i found ArgumentCaptor, where i can get the object from method call:

Declaring the Captor:

@Captor
ArgumentCaptor<Client> clientCaptor;

Using at test method:

Mockito.when(clientRepository.save(clientCaptor.capture())).thenReturn(client); //<-- capturing the result
clientService.save(dto);
Client saved = clientCaptor.getValue() //getting object

Assertions.assertEquals(dto.getReturnDate().plusMinutes(30), saved.getReturnDate()); //assertion
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文