2016-11-26 75 views
1

Spring似乎在我的测试环境中随机加载了bean。在Spock集成测试中嘲笑JPA存储库

我有如下库类User

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

    User findOneByExternalId(Long externalId); 

    Optional<User> findOneById(Long id); 

} 

,它的测试相当于:

@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; 
     } 
    } 

} 

,另外两个为Device

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

    Optional<Device> findOneByDeviceId(String deviceId); 

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

} 

测试相当于:

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

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

} 

测试下面通过对UserRepository,而不是为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 
    } 

} 

可能是什么原因?我重复了applicationContext的内容,它清楚地表明我的UserRepository bean的名称为userRepository,我的DeviceRepository的名称为deviceRepository

这里的输出从测试:

Condition not satisfied: 

clazz.isAssignableFrom(applicationContext.getBean(bean).getClass()) 
|  |    |     |  |  | 
|  false   |     |  |  class com.sun.proxy.$Proxy143 
|      |     |  interface com.example.repository.DeviceRepository 
|      |     org.[email protected]10e4cf09 
|      org.s[email protected]7dc51783: startup date [Sun Nov 27 22:09:16 CET 2016]; parent: org.spring[email protected]56aaaecd 
interface com.example.test.integration.mock.TestDeviceRepository 
+1

它是如何失败?什么信息? – Opal

+1

如何删除'@ Primary'注释? –

+0

@Opal它说'DeviceRepository' bean不是'TestDeviceRepository'的一个实例。我认为这很明显,对不起!错误中有关于DeviceRepository类是否是代理的信息(如预期的那样,毕竟它是JPA魔术),所以没有什么特别的用处。 – Jezor

回答

3

最简单的解决方案,有时最难以想到的。我承认我太过分地解决了这个问题。

我不得不这样做的是使用@Profile注释,如:

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

,并在测试类

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

现在我所有的测试都通过!