Search code examples
spring-bootspock

Spock mock repository findAll always return null


[Service]

@Service
@RequiredArgsConstructor
public class RecordService {
    private final RecordRepository recordRepository;


    @Transactional
    public void bulkUpdateRecord(BulkUpdateRecordRequest[] requestDto) {
        Map<Long, BulkUpdateRecordRequest> recordsMap = Arrays.stream(requestDto)
                .collect(Collectors.toMap(BulkUpdateRecordRequest::getId, record -> record));
        List<Record> records = recordRepository.findAllById(recordsMap.keySet());
        System.out.println("records = " + records);
    }
}

[Repository]

public interface RecordRepository extends JpaRepository<Record, Long>, RecordCustomRepository {
}

[Test codes]

class RecordServiceTest extends Specification {

    RecordRepository recordMockRepo = Mock()
    RecordService recordService = new RecordService(recordMockRepo)

    def "bulkUpdateRecord"() {
        given:
        def request = new BulkUpdateRecordRequest()
        request.setId(1)
        request.setCount(20)
        request.setWeight(100)
        request.setWeightType(WeightType.KG)
        def record = Record.builder()
                .id(1L)
                .weightType(request.getWeightType())
                .weight(request.getWeight())
                .count(request.getCount())
                .recordType(RecordType.PERSONAL)
                .exerciseName("deadlift")
                .exerciseType(ExerciseType.BACK)
                .build()

        when:
        recordService.bulkUpdateRecord(request)

        then:
        recordMockRepo.findAllById(_ as List) >> [record]
    }
}

You know that I mocked findAllById() method that return [record]

But it always return null.

However, this problem does not occur with methods that look up a single entity like findBy~().

Is there any issue on my code?

Thanks.


Solution

  • It is because this:

    recordMockRepo.findAllById(_ as List) >> [record]
    

    ... does not match to a call in the RecordService class:

    recordRepository.findAllById(recordsMap.keySet());
    

    Because recordsMap.keySet() returns Set and not List. Change it on:

    recordMockRepo.findAllById(_ as Set) >> [record]
    

    And when you have the mock instruction without invocation count checking then it is better to have it in the given section, because it is not testing anything and does not belong to then section. Or you can add the test of invocation count like this:

    1 * recordMockRepo.findAllById(_ as Set) >> [record]