我正在努力彻底理解 Spring Boot,尤其是测试。
我希望所有测试都针对 src/test/resources 内的 application.properties 中的数据库运行,无论活动配置文件如何。但由于某种原因它只查询 src/main/resources 数据库。
我现在创建了以下配置文件(也许这些名称没有意义):
我通过脚本文件创建了两个具有相同架构和功能的数据库:
我在 src/test/resources/db/Data.sql 中还有一个单独的 Data.sql 文件
我有一个正在运行的本地 Postgres 数据库,因为我使用的是 Postgres,所以我觉得不需要任何测试容器或 H2,我只是在同一实例上创建了另一个数据库以进行本地测试,这是可以接受的吗?
据我所知,src/test/resources 中的所有内容都应该用于测试,但不知何故,所有测试都针对活动配置文件中的任何数据库运行。
由于某种原因,所有@DataJpaTests和@SpringBootTests都在src/test/resources/db/Data.sql中查找Data.sql脚本, 但由于某种原因,它正在针对 src/main/resources 文件内的活动配置文件中定义的数据库运行测试。
我只添加了我认为对于这个问题必要的代码,但我会很乐意编辑它并提供更多细节。
这是代码:
SQL
TRUNCATE serverappsplayground.DummyEntity RESTART IDENTITY CASCADE ;
INSERT INTO serverappsplayground.DummyEntity (name, key, value, x, y, z)
VALUES
('DE-Name 1', 'key-1', 'value-1', 65, 33, FLOOR(RANDOM() * 1000)),
('DE-Name 2', 'key-2', 'value-2', 47, 96, FLOOR(RANDOM() * 1000)),
('DE-Name 3', 'key-3', 'value-3', 22, 34, FLOOR(RANDOM() * 1000)),
('DE-Name 4', 'key-4', 'value-4', 77, 56, FLOOR(RANDOM() * 1000)),
('DE-Name 5', 'key-5', 'value-5', 89, 17, FLOOR(RANDOM() * 1000)),
('DE-Name 6', 'key-6', 'value-1', 4, 78, FLOOR(RANDOM() * 1000)),
('DE-Name 7', 'key-7', 'value-2', 13, 8, FLOOR(RANDOM() * 1000)),
('DE-Name 8', 'key-8', 'value-8', 67, 10, FLOOR(RANDOM() * 1000)),
('DE-Name 9', 'key-9', 'value-9', 56, 2, FLOOR(RANDOM() * 1000)),
('DE-Name 10', 'key-10', 'value-10', 99, 43, FLOOR(RANDOM() * 1000)),
('DE-Name 11', 'key-11', 'value-11', 65, 33, FLOOR(RANDOM() * 1000)),
('DE-Name 12', 'key-12', 'value-12', 47, 96, FLOOR(RANDOM() * 1000)),
('DE-Name 13', 'key-13', 'value-13', 22, 34, FLOOR(RANDOM() * 1000)),
('DE-Name 14', 'key-14', 'value-14', 77, 56, FLOOR(RANDOM() * 1000)),
('DE-Name 15', 'key-15', 'value-15', 89, 17, FLOOR(RANDOM() * 1000)),
('DE-Name 16', 'key-16', 'value-16', 4, 78, FLOOR(RANDOM() * 1000)),
('DE-Name 17', 'key-17', 'value-17', 13, 8, FLOOR(RANDOM() * 1000)),
('DE-Name 18', 'key-18', 'value-18', 67, 10, FLOOR(RANDOM() * 1000)),
('DE-Name 19', 'key-19', 'value-19', 56, 2, FLOOR(RANDOM() * 1000)),
('DE-Name 20', 'key-20', 'value-20', 99, 43, FLOOR(RANDOM() * 1000));
配置:
应用程序.yml
spring:
# Set the application name and description:
application:
name: "SpringBootWebMvcJavaFoundation"
description: "This is the fundamental foundation project for Spring Boot"
main:
keep-alive: true
# Setting the profile
profiles.active: stage
# Enabling virtual threads
# This is extremely important in order to maximise performance and make the most of Java 21
threads.virtual.enabled: true
# Data access layer
jpa:
hibernate:
# This property is extremely important as I want to remove Spring Boot making queries with those underscores by default:
naming.physical-strategy: "org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl"
# Here we make sure Spring Data JPA does not mess around with my database as I don't want it too,
# It makes sure there are no ddl statements in any profile
ddl-auto: none
test:
database:
replace: none
应用程序-tdd.yml:
spring:
sql:
init:
mode: always
# Adding the classpath prefix to all paths,
# and then following the path as normal works for tests + when app context is loaded
# Note: Schema generation does not need to happen everytime, I can also manually load the schema,
# This makes tests slow, so I must simply aware, anytime changes are made too Schema or functions,
# Either uncomment this to be safe or remember and manually modify the schema with psql,
#schema-locations: classpath:db/Schema.sql,classpath:db/Functions.sql
data-locations: classpath:db/Data.sql
datasource:
url: jdbc:postgresql://localhost:5432/MythicalLearnTest
jpa:
show-sql: 'true'
testpropertyexists: 'yes'
应用程序阶段.yml
spring:
sql:
init:
mode: always
#schema-locations: classpath:db/Schema.sql,classpath:db/Functions.sql
#data-locations: classpath:db/Data.sql
datasource:
url: "jdbc:postgresql://localhost:5432/MythicalLearn"
src/test/resources 中的application.properties:
spring.sql.init.mode=always
spring.datasource.url=jdbc:postgresql://localhost:5432/MythicalLearnTest
spring.sql.init.data-locations=classpath:db/Data.sql
测试代码
@DataJpaTest基类:
@org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class DataJpaTest {
}
class DummyJpaServiceDbTest extends DataJpaTest {
private DummyJpaService dummyJpaService;
@Autowired
private DummyJpaRepo dummyJpaRepo;
@BeforeEach
void setUp() {
dummyJpaService = new DummyJpaService(dummyJpaRepo);
}
@Test
void works() {
assertTrue(true);
}
@Test
void getAllDummies() {
assertEquals(
20,
dummyJpaService.getAllDummies().size()
);
}
@Test
void getDummyById() {
assertEquals(
"key-7",
dummyJpaService.getDummyById(7).get().getKey()
);
}
@Test
void createDummy() {
DummyEntity entity = new DummyEntity();
entity.setKey("key-222");
dummyJpaService.createDummy(entity);
assertEquals(21, dummyJpaService.getAllDummies().size());
}
@Test
void updateDummy() {
DummyEntity entity = dummyJpaService.getDummyById(7).get();
entity.setName("UPDATED DE7");
dummyJpaService.updateDummy(entity);
assertEquals("UPDATED DE7", dummyJpaService.getDummyById(7).get().getName());
}
@Test
void deleteDummy() {
DummyEntity entity = dummyJpaService.getDummyById(20).get();
dummyJpaService.deleteDummy(entity);
assertEquals(19, dummyJpaService.getAllDummies().size());
}
@Test
void deleteDummyById() {
DummyEntity entity = dummyJpaService.getDummyById(20).get();
dummyJpaService.deleteDummyById(entity.getId());
assertEquals(19, dummyJpaService.getAllDummies().size());
}
}
@SpringBootTest
@SpringBootTest
@AutoConfigureMockMvc
@Sql(scripts = "classpath:db/Data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
public class SpringBootJavaApplicationTests {
@Test
void contextLoads() {
}
}
class DummyApiServiceIntegrationTest extends SpringBootJavaApplicationTests {
@Autowired
private MockMvc mvc;
private String basePath = "/dummy-entity-api";
@Autowired
private ObjectMapper mapper;
@BeforeEach
void setUp() {
}
@Test
@DisplayName("Checking and hoping the real database is loaded for tests")
void getAllDummies() throws Exception {
MvcResult result = mvc.perform(
get(basePath + "/dummies")
).andReturn();
assertThat(result.getResponse().getContentAsString()).isNotBlank();
}
@Test
@DisplayName("Testing the response returns the 20 lists that are in the dummy data")
void getAllDummiesObjects() throws Exception {
MvcResult result = mvc.perform(
get(basePath + "/dummies")
).andReturn();
//Use the arrrays.asList because mapper returns an array:
List<DummyEntity> dummyEntityList = getDummyListFromJson(
result.getResponse().getContentAsString()
);
assertThat(dummyEntityList.size()).isEqualTo(20);
}
@Test
@DisplayName("When id not found then we get 404")
void getByIdNotFound() throws Exception {
mvc.perform(
get(basePath + "/{25}", 25)
).andExpect(status().isNotFound());
}
@Test
@DisplayName("When id found then it is 200")
void getByIdFound() throws Exception {
mvc.perform(
get(basePath + "/{1}", 1)
).andExpect(status().isOk());
}
@Test
@DisplayName("Testing that it creates a new entity")
void testCreates() throws Exception {
DummyEntity dummyEntity = new DummyEntity();
dummyEntity.setName("DE-Created By Spring Boot test");
dummyEntity.setKey("key-21");
dummyEntity.setValue("value-21");
dummyEntity.setXYZ(1,2,3);
MvcResult result = mvc.perform(
post(basePath + "/create")
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(dummyEntity))
)
.andReturn();
assertThat(result.getResponse().getStatus()).isEqualTo(201);
}
@Test
@DisplayName("Here i am testing that the extra entity is added, but then on each load it is reset")
void testExtraEnttityIsAdded() throws Exception {
DummyEntity dummyEntity = new DummyEntity();
dummyEntity.setName("DE-Created By Spring Boot test");
dummyEntity.setKey("key-21");
dummyEntity.setValue("value-21");
dummyEntity.setXYZ(1,2,3);
mvc.perform(
post(basePath + "/create")
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(dummyEntity))
)
.andReturn();
//Not a very readable expression, but later I can learn
assertThat(
getDummyListFromJson(
mvc.perform(
get(basePath + "/dummies")
)
.andReturn()
.getResponse()
.getContentAsString()
).size()
).isEqualTo(21);
//Getting the list so I can see it should be 21:
}
/**
* Keeping a private function that gets a List from JSON String,
* So I do not have to repeat myself multiple times:
*/
private List<DummyEntity> getDummyListFromJson(String jsonList) throws Exception {
return Arrays.asList(
mapper.readValue(
jsonList,
DummyEntity[].class
)
);
}
}
现在,我有两个独立的数据库,但是当我在暂存配置文件中运行测试时,它会在 test/resources 中找到 Data.sql 脚本,但由于某种原因,不会针对测试数据库运行测试:
我已经多次截断表格,同样的事情发生了
如何让所有测试仅针对测试数据库运行,而不管配置文件如何? 这可能吗? 或者也许,我想做的事情很愚蠢,并且有更好的工作流程?
我忍不住想,这是一件非常简单的事情,甚至没有提到,但我不明白。 我将不胜感激任何建议
现在发生的情况是,两个文件(
src/test/resources/application.properties
和 src/main/resources/application.yml
)中的密钥已合并,因此 spring.profiles.active
密钥出现在您的测试中。
将您的
src/test/resources/application.properties
重命名为 src/test/resources/application.yml
。这将覆盖 src/main/resources/application.yml
。所以现在只有来自 src/test/resources/application.yml
的键才会出现在测试中。