简体   繁体   中英

Mocking JPA repository in Spock integration tests

Spring seems to load beans randomly in my test context.

I have following repository classes for User :

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    User findOneByExternalId(Long externalId);

    Optional<User> findOneById(Long id);

}

and it's test equivalent:

@Primary
@Repository(value = "userRepository")
public interface TestUserRepository extends UserRepository {

    Long TEST_CORRECT_USER_ID = 1L;
    Long TEST_INCORRECT_USER_ID = 2L;

    @Override
    default User findOneByExternalId(Long externalId) {
        return getTestUser(externalId);
    }

    @Override
    default Optional<User> findOneById(Long id) {
        return ofNullable(getTestUser(id));
    }

    default User getTestUser(Long id) {
        if (TEST_CORRECT_USER_ID.equals(id)) {
            User user = new User();
            user.setExternalId(id);
            user.setDevices(emptyList());
            user.setId(id);
            return user;
        }
        else {
            return null;
        }
    }

}

and two more for Device :

@Repository
public interface DeviceRepository extends JpaRepository<Device, Long> {

    Optional<Device> findOneByDeviceId(String deviceId);

    Optional<Device> findOneByDeviceIdAndToken(String deviceId, String token);

}

test equivalent:

@Primary
@Repository(value = "deviceRepository")
public interface TestDeviceRepository extends DeviceRepository {

    @Override
    default <S extends Device> S save(S device) {
        return device;
    }

}

the test below is passing for the UserRepository , but not for the DeviceRepository :

@SpringBootTest(classes = Application)
@ContextConfiguration(classes = [TestDeviceRepository, TestUserRepository])
class IntegrationContextSpecTest extends Specification {

    @Autowired
    ApplicationContext applicationContext

    @Unroll("Bean #bean should be instance of #clazz")
    def "should initialize test beans instead of normal beans"() {
        expect:
        clazz.isAssignableFrom(applicationContext.getBean(bean).
                                       getClass())

        where:
        bean             | clazz
        UserRepository   | TestUserRepository
        DeviceRepository | TestDeviceRepository
    }

}

What might be the cause of it? I iterated over applicationContext contents and it clearly says that my UserRepository bean have a name userRepository and my DeviceRepository have a name deviceRepository .

Here's the output from test:

Condition not satisfied:

clazz.isAssignableFrom(applicationContext.getBean(bean).getClass())
|     |                |                  |       |     |
|     false            |                  |       |     class com.sun.proxy.$Proxy143
|                      |                  |       interface com.example.repository.DeviceRepository
|                      |                  org.springframework.data.jpa.repository.support.SimpleJpaRepository@10e4cf09
|                      org.springframework.web.context.support.GenericWebApplicationContext@7dc51783: startup date [Sun Nov 27 22:09:16 CET 2016]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@56aaaecd
interface com.example.test.integration.mock.TestDeviceRepository

The simplest solutions are sometimes the most difficult to think of. I admit that I was overthinking the problem too much.

All I had to do is use @Profile annotation like:

@Repository
@Profile("!test")
public interface DeviceRepository extends JpaRepository<Device, Long> { 
    /* ... implementation... */ 
}

and in the test class

@Repository
@Profile("test")
public interface TestDeviceRepository extends DeviceRepository { 
    /* ... implementation... */ 
}

And now all my tests are passing!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM