注入的转换器在我的测试类中无法识别,即使我在日志文件条目中清楚地看到转换器已成功注入。 注意:我正在使用一个非常规数据库以及 GraphUnit 来进行Spring数据存储库单元测试。
TestContextConfiguration
@Configuration
@ComponentScan(basePackages = "com.example.analytics",
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Configuration.class),
@ComponentScan.Filter(type = FilterType.REGEX, pattern = { "com.example.analytics.config.DatabaseConnectionProperties" })
})
@EnableNeo4jRepositories("com.example.analytics.repository")
@EnableTransactionManagement(mode = AdviceMode.PROXY)
@EnableAutoConfiguration(exclude = { MainConfiguration.class, DatabaseConnectionConfiguration.class })
public class TestContextConfiguration extends Neo4jConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(TestContextConfiguration.class);
@Autowired
private StringToLocalDateTimeConverter stringToLocalDateTimeConverter;
@Autowired
private LocalDateTimeToStringConverter localDateTimeToStringConverter;
public TestContextConfiguration() {
setBasePackage("com.example.analytics.model");
}
@Bean(name = "graphDatabaseService", destroyMethod = "shutdown")
public GraphDatabaseService getGraphDatabaseService() {
LOG.debug("Returning an impermanent database for test context.");
return new TestGraphDatabaseFactory().newImpermanentDatabaseBuilder()
.setConfig(GraphDatabaseSettings.nodestore_mapped_memory_size, "10M")
.setConfig(GraphDatabaseSettings.string_block_size, "60")
.setConfig(GraphDatabaseSettings.array_block_size, "300")
.newGraphDatabase();
}
@Bean
@DependsOn("graphDatabaseService")
public Neo4jTemplate neo4jTemplate() {
return new Neo4jTemplate(getGraphDatabaseService());
}
public TypeRepresentationStrategy<Relationship> relationshipTypeRepresentationStrategy() throws Exception {
return new NoopRelationshipTypeRepresentationStrategy();
}
@Bean
@DependsOn({ "stringToLocalDateTimeConverter", "localDateTimeToStringConverter" })
protected ConversionService neo4jConversionService() throws Exception {
LOG.debug("Adding local date time to string and vice versa converters to TEST Context ...");
ConversionService conversionService = super.neo4jConversionService();
ConverterRegistry registry = (ConverterRegistry) conversionService;
if(stringToLocalDateTimeConverter == null )
LOG.warn("stringToLocalDateTimeConverter was NOT injected!");
if(localDateTimeToStringConverter == null )
LOG.warn("localDateTimeToStringConverter was NOT injected!");
registry.addConverter(stringToLocalDateTimeConverter);
registry.addConverter(localDateTimeToStringConverter);
LOG.debug("Addition of Converter from LocalDateTime to String and vice-versa to TEST context has been completed!");
return conversionService;
}
}
LocalDateTimeToStringConverter
@Component
public class LocalDateTimeToStringConverter implements Converter<LocalDateTime, String> {
private static final Logger LOG = LoggerFactory.getLogger(LocalDateTimeToStringConverter.class);
@Value("${neo4j.dateTime.format:yyyy-MM-dd HH:mm:ss}")
private String dateTimeFormat;
@Override
public String convert(@NonNull final LocalDateTime source) {
LOG.debug("Converting LocalDateTime into String using the format: {}", dateTimeFormat);
return String.valueOf(source.format(DateTimeFormatter.ofPattern(dateTimeFormat)));
}
}
StringToLocalDateTimeConverter
@Component
public class StringToLocalDateTimeConverter implements Converter<String, LocalDateTime> {
private static final Logger LOG = LoggerFactory.getLogger(StringToLocalDateTimeConverter.class);
@Value("${neo4j.dateTime.format:yyyy-MM-dd HH:mm:ss}")
private String dateTimeFormat;
/**
* Convert the source of type S to target type T.
*
* @param source the source object to convert, which must be an instance of S (never {@code null})
* @return the converted object, which must be an instance of T (potentially {@code null})
* @throws IllegalArgumentException if the source could not be converted to the desired target type
*/
@Override
public LocalDateTime convert(@NonNull final String source) {
return LocalDateTime.parse(source, DateTimeFormatter.ofPattern(dateTimeFormat));
}
@PostConstruct
public void uponConstruction(){
LOG.debug("Construction of the class {} has been completed!", this.getClass().getName());
LOG.debug("Date time format has been initialised to {} ", dateTimeFormat);
}
}
抽象测试类
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestContextConfiguration.class)
@TestExecutionListeners(inheritListeners = false, listeners = { DataSourceDependencyInjectionTestExecutionListener.class })
public abstract class AbstractRepositoryTest<T extends DatabasePopulator> {
public static final String RESET_DATABASE_CYPHER = "MATCH (n) OPTIONAL MATCH (n)-[r]-() DELETE r, n";
private static final Logger LOG = LoggerFactory.getLogger(AbstractRepositoryTest.class);
public static final Integer DEFAULT_PAGE_NUMBER = 0;
public static final Integer DEFAULT_PAGE_SIZE = 20;
protected static GraphDatabaseService graphDatabaseService;
protected static ExecutionEngine executionEngine;
protected T databasePopulator;
public AbstractRepositoryTest() {
this.databasePopulator = assignDatabasePopulator();
}
@BeforeClass
public static void initialiseEmbeddedDatabase() {
LOG.debug("Initialising embedded temporary graph database for executing unit tests ...");
executionEngine = new ExecutionEngine(graphDatabaseService);
}
@AfterClass
public static void shutdownEmbeddedDatabase() {
LOG.debug("Shutting down embedded temporary graph database ...");
graphDatabaseService.shutdown();
}
@Autowired
public void setGraphDatabaseService(final GraphDatabaseService graphDatabaseService) {
LOG.debug("Injecting embedded graph database instance ...");
AbstractRepositoryTest.graphDatabaseService = graphDatabaseService;
}
public abstract T assignDatabasePopulator();
@Before
public void setUpTestData() {
databasePopulator.populate(graphDatabaseService);
LOG.debug("Temporary database has been successfully populated with test data-set!");
}
@After
public void tearDown() {
LOG.debug("Emptying the temporary database used for unit test ...");
if (executionEngine != null) {
executionEngine.execute(RESET_DATABASE_CYPHER);
LOG.debug("Temporary database has been emptied!");
}
}
protected Pageable getDefaultPageable() {
BiFunction<Integer, Integer, Pageable> biFunction = PageRequest::new;
return biFunction.apply(DEFAULT_PAGE_NUMBER, DEFAULT_PAGE_SIZE);
}
}
实际测试类
public class PersonRepositoryTest extends AbstractRepositoryTest<CypherFilesPopulator> {
public static final String CQL_DATASET_FILE = "src/test/resources/person-repository-dataset.cql";
private static final Logger LOG = LoggerFactory.getLogger(PersonRepositoryTest.class);
@Autowired
private PersonRepository personRepository;
@Test
public void should_find_person_with_multiple_accounts() {
final List<Person> persons = personRepository.findOnesWithSeveralAccounts(getDefaultPageable()).getContent();
assertThat(persons, hasSize(1));
Person expectedResult = new PersonBuilder()
.setTitle("Prof.").setFirstName("Helen").setLastName("Olson")
.setDateOfBirth(LocalDateTime.of(1989, 10, 19, 6, 41, 24))
.createPerson();
assertThat(persons, hasItem(expectedResult));
}
@Override
public CypherFilesPopulator assignDatabasePopulator() {
return new CypherFilesPopulator() {
private final Logger LOGGER = LoggerFactory.getLogger(CypherFilesPopulator.class);
@Override
protected String[] files() throws IOException {
LOGGER.debug("Initialising cypher files populator ....");
return new String[]{ CQL_DATASET_FILE };
}
};
}
}
记录文件条目
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.2.4.RELEASE)
2015-09-08 12:15:21,596 INFO nalytics.repository.PersonRepositoryTest: 47 - Starting PersonRepositoryTest on Viswanaths-MacBook-Pro.local with PID 1175 (/Users/viswanathj/projects/myproject/xyz-cleanup-utility/target/test-classes started by viswanathj in /Users/viswanathj/projects/myproject/xyz-cleanup-utility)
2015-09-08 12:15:21,597 DEBUG nalytics.repository.PersonRepositoryTest: 50 - Running with Spring Boot v1.2.4.RELEASE, Spring v4.1.6.RELEASE
2015-09-08 12:15:21,804 INFO ation.AnnotationConfigApplicationContext: 510 - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@63070bab: startup date [Tue Sep 08 12:15:21 CEST 2015]; root of context hierarchy
2015-09-08 12:15:22,587 INFO ion.AutowiredAnnotationBeanPostProcessor: 153 - JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2015-09-08 12:15:22,795 DEBUG nalytics.config.TestContextConfiguration: 53 - Returning an impermanent database for test context.
2015-09-08 12:15:23,407 DEBUG converter.StringToLocalDateTimeConverter: 38 - Construction of the class com.example.analytics.converter.StringToLocalDateTimeConverter has been completed!
2015-09-08 12:15:23,408 DEBUG converter.StringToLocalDateTimeConverter: 39 - Date time format has been initialised to yyyy-MM-dd HH:mm:ss
2015-09-08 12:15:23,414 DEBUG n.analytics.report.client.InfogramClient: 43 - Access to Infogr.am REST API service is set-up using your Infogr.am API account ...
2015-09-08 12:15:23,414 DEBUG n.analytics.report.client.InfogramClient: 44 - Henceforth, each request to the Infogr.am REST API service will be signed along with 'api_key' parameter
2015-09-08 12:15:25,007 DEBUG nalytics.config.TestContextConfiguration: 75 - Adding local date time to string and vice versa converters to conversion service to TEST Context ...
2015-09-08 12:15:25,008 DEBUG nalytics.config.TestContextConfiguration: 86 - Addition of Converter from LocalDateTime to String and vice-versa to TEST context has been completed!
2015-09-08 12:15:25,029 INFO rk.transaction.jta.JtaTransactionManager: 490 - Using JTA UserTransaction: org.neo4j.kernel.impl.transaction.UserTransactionImpl@4a9869a8
2015-09-08 12:15:25,030 INFO rk.transaction.jta.JtaTransactionManager: 501 - Using JTA TransactionManager: org.neo4j.kernel.impl.transaction.SpringTransactionManager@75e0a54c
2015-09-08 12:15:25,122 INFO roperties$SimpleAuthenticationProperties: 403 -
Using default password for shell access: <password was here>
2015-09-08 12:15:25,153 INFO .CrshAutoConfiguration$CrshBootstrapBean: 125 - Configuring property ssh.port=2000 from properties
2015-09-08 12:15:25,154 INFO .CrshAutoConfiguration$CrshBootstrapBean: 125 - Configuring property ssh.auth_timeout=600000 from properties
2015-09-08 12:15:25,154 INFO .CrshAutoConfiguration$CrshBootstrapBean: 125 - Configuring property ssh.idle_timeout=600000 from properties
2015-09-08 12:15:25,154 INFO .CrshAutoConfiguration$CrshBootstrapBean: 125 - Configuring property ssh.default_encoding=UTF-8 from properties
2015-09-08 12:15:25,155 INFO .CrshAutoConfiguration$CrshBootstrapBean: 125 - Configuring property auth=simple from properties
2015-09-08 12:15:25,155 INFO .CrshAutoConfiguration$CrshBootstrapBean: 125 - Configuring property auth.simple.username=user from properties
2015-09-08 12:15:25,155 INFO .CrshAutoConfiguration$CrshBootstrapBean: 125 - Configuring property auth.simple.password=<password was here> from properties
2015-09-08 12:15:26,255 INFO nalytics.repository.PersonRepositoryTest: 56 - Started PersonRepositoryTest in 4.88 seconds (JVM running for 5.387)
2015-09-08 12:15:26,259 DEBUG lytics.repository.AbstractRepositoryTest: 59 - Injecting embedded graph database instance ...
2015-09-08 12:15:26,260 DEBUG lytics.repository.AbstractRepositoryTest: 47 - Initialising embedded temporary graph database for executing unit tests ...
2015-09-08 12:15:26,674 DEBUG lytics.repository.AbstractRepositoryTest: 68 - Temporary database has been successfully populated with test data-set!
2015-09-08 12:15:26,817 INFO eldaccess.DelegatingFieldAccessorFactory: 74 - No FieldAccessor configured for field: class java.time.LocalDateTime dateOfBirth rel: false idx: false
2015-09-08 12:15:26,831 DEBUG lytics.repository.AbstractRepositoryTest: 74 - Emptying the temporary database used for unit test ...
2015-09-08 12:15:26,855 DEBUG lytics.repository.AbstractRepositoryTest: 77 - Temporary database has been emptied!
java.lang.AssertionError:
Expected: a collection containing <Person{title='Prof.', firstName='Helen', lastName='Olson', dateOfBirth=1989-10-19T06:41:24}>
but: was <Person{title='Prof.', firstName='Helen', lastName='Olson', dateOfBirth=null}>F
我用来预先填充我的非永久性数据库的cypher文件的内容如下所示
// Create 5 person nodes
MERGE (p1:Person {title:'Prof.', firstName:'Helen', lastName:'Olson', dateOfBirth:'1989-10-19 06:41:24'});
MERGE (p2:Person {title:'Dr.', firstName:'Bruce', lastName:'Hermiston', dateOfBirth:'1992-10-03 10:54:21'});
MERGE (p3:Person {title:'Mr.', firstName:'Regan', lastName:'Rice', dateOfBirth:'1973-10-05 00:43:54'});
MERGE (p4:Person {title:'Prof.', firstName:'Alysha', lastName:'Crooks', dateOfBirth:'1976-01-15 20:13:31'});
MERGE (p5:Person {title:'Prof.', firstName:'Arturo', lastName:'Turner', dateOfBirth:'1989-07-11 03:30:21'});
MATCH (p:Person) set p:_Person;
有人可以帮忙解释一下我在这里缺少什么吗?