0

I have this code.

@RunWith(SpringRunner.class)
@SpringBootTest(
        webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT,
        classes = ApiDbApplication.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@TestPropertySource(
        locations = "classpath:application.yml")
@ExtendWith(SpringExtension.class)
@Transactional
public class LocationIT {

    @MockBean
    CompanyRepository companyRepository;
    @MockBean
    ShipmentRepository shipmentRepository;
    @MockBean
    ContactRepository contactRepository;

    private LocationController locationController;
    private LocationService locationService;

    @Autowired
    LocationRepository locationRepository;

    @LocalServerPort
    private int port;
    TestRestTemplate restTemplate = new TestRestTemplate();
    HttpHeaders headers = new HttpHeaders();

    @Before
    public void setup() {
        locationService = new LocationService(locationRepository);
        this.locationController = new LocationController(locationService);
    }



    @Test
    public void testAddLocation() {
        ObjectMapper mapper = new ObjectMapper()
                .registerModule(new JavaTimeModule());
        ;
        Location location = Location.builder()
                .id(Long.valueOf(7))
                .city("Fayetteville")
                .lat(32.33)
                .lon(37.49)
                .name("Big place")
                .State("Arkansas").build();

        ResponseEntity<String> responseEntity = this.restTemplate
                .postForEntity("http://localhost:" + port + "/api/location/save", location, String.class);

        ResponseEntity<List<Location>> results = restTemplate.exchange("http://localhost:" + port + "/api/location/list",
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<Location>>(){});


        assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
        assertEquals(HttpStatus.OK, results.getStatusCode());
        assertEquals(Collections.singletonList(location), results.getBody());

    }
}

Whenever I run the test. My location repository is null and I have the @Repository annotation. This is the error I get: No qualifying bean of type 'com.example.apidb.location.LocationRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

I want to hit the endpoint using restTemplate, so I would rather not use @DataJPATest.

This question is similar: How can I use @SpringBootTest(webEnvironment) with @DataJpaTest?

samabcde
  • 6,988
  • 2
  • 25
  • 41
Kado
  • 13
  • 2
  • 2
    You can try adding @EnableJpaRepositories(basePackageClasses = { LocationRepository.class} – johnnyutts Sep 21 '22 at 08:55
  • johhnyutts That worked. Thanks! – Kado Sep 21 '22 at 09:23
  • The problem is that you are probably mixing Junit4 and JUnit5 in your unit test which breaks things. I would remove the `@RunWith` and `@ExtendWIth` (the latter is already available on the `@SpringBootTest` annotation). I assume you want to use JUnit5 here and not JUnit4. Also make sure the `@Test` annotation is from the proper package.You should inject the `TestRestTemplate` and remove your `@Before` method (constructing the controller in this test doesn't add anything). – M. Deinum Sep 21 '22 at 10:58
  • @M.Deinum I tried removing the EnableJPARepositories. I changed the test to be jupiter, removed runwith, and extendwith. I still get the error for repository without the EnableJPARepositories. – Kado Sep 22 '22 at 08:17
  • You should also remove the `@TestPropertySource` as you cannot load yml files with it. Please update the question with what you have now. Basically when you need to put configuration anntations on your test (those `@Enable*` or `@Import`) you are generally doing it wrong. Hence adding `@EnableJpaRepositories` isn't the solution. On a different note I see no use of injecting that repository in your test (as I also mentioned the `@Before` is useless). So you either aren't showing the full test or it really contains things that aren't useful. – M. Deinum Sep 22 '22 at 08:21
  • @M.Deinum It's working now. Thanks! I think just ran clean a couple times and it worked, so I will make those changes. The Before is useless. I was just trying to test something. – Kado Sep 22 '22 at 08:41

2 Answers2

0

Johhnyutts answered the question. The answer was to add @EnableJpaRepositories(basePackageClasses = { LocationRepository.class}

Kado
  • 13
  • 2
0

If the test case you are running is the actual one in your post you are doing things wrong

  1. You are mixing JUnit4 and JUnit5, that won't work in a single class.
  2. The @TestPropertySource is for property files not yaml files
  3. You should autowire the TestRestTemplate not create it (this also allows you to remove the @LocalServerPort as that is setup already as a base URL.
  4. Your @Before doesn't really make sense, constructing the service and controller don't add anything in your test, it only takes up memory and execution time.
  5. The ObjectMapper inside your test method isn't used, so why construct it.
  6. The @SpringBootTest can figure out the application class itself.
  7. The @AutoConfigureTestDatabase isn't needed, that is only for sliced tests like @DataJpaTest, @DataJdbcTest etc.

That all being said I would expect something like the following to work

Assuming you configured a proper datasource in your application.yml in your src/test/resources.


import org.junit.jupiter.api.Test

@SpringBootTest(
        webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT,
        )
class LocationIT {

    @MockBean
    private CompanyRepository companyRepository;
    @MockBean
    private ShipmentRepository shipmentRepository;
    @MockBean
    private ContactRepository contactRepository;
    
    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void testAddLocation() {       
        Location location = Location.builder()
                .id(Long.valueOf(7))
                .city("Fayetteville")
                .lat(32.33)
                .lon(37.49)
                .name("Big place")
                .State("Arkansas").build();

        ResponseEntity<String> responseEntity = this.restTemplate
                .postForEntity("/api/location/save", location, String.class);

        ResponseEntity<List<Location>> results = restTemplate.exchange("/api/location/list",
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<Location>>(){});

        assertEquals(HttpStatus.OK, responseEntity.getStatusCode());
        assertEquals(HttpStatus.OK, results.getStatusCode());
        assertEquals(Collections.singletonList(location), results.getBody());
    }
}
M. Deinum
  • 115,695
  • 22
  • 220
  • 224