我有一个带有 SpringBoot2 和 Junit5 的应用程序,现在我正在尝试进行测试。我有一个名为 OrderService 的类,如下所示:
@Component
public class OrderService {
@Value("#{'${food.requires.box}'.split(',')}")
private List<String> foodRequiresBox;
@Value("#{'${properties.prioritization}'.split(',')}")
private List<String> prioritizationProperties;
@Value("${further.distance}")
private Integer slotMeterRange;
@Value("${slot.meters.long}")
private Double slotMetersLong;
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,该类有许多 @Value 注释,用于从 application.properties 文件中提取值。
在 POM 文件中,我有以下依赖项:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>2.0.5.RELEASE</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
在test/resources文件夹中,我有包含以下信息的 application.properties 文件:
properties.prioritization:vip,food
food.requires.box:pizza,cake,flamingo
further.distance:2
slot.meters.long:0.5
Run Code Online (Sandbox Code Playgroud)
测试文件如下所示:
properties.prioritization:vip,food
food.requires.box:pizza,cake,flamingo
further.distance:2
slot.meters.long:0.5
Run Code Online (Sandbox Code Playgroud)
但测试在尝试使用foodRequiresBox时会抛出 …
我尝试为单元测试加载第二个属性文件,这会覆盖一些属性。
@PropertySource用a加载它@Configuration不起作用,用 a 加载它@TestPropertySource也不起作用。仅properties直接设置@TesPropertySource有效,但当我尝试将其变成元注释时它不起作用。
这是一个示例项目:https ://github.com/cptwunderlich/SpringTestProperties
我更喜欢加载一个文件来影响所有测试(例如 with @PropertySource),但如果这不起作用,至少有一个自定义元注释会很好,所以我不必将其放在每个测试上测试。基本上我不想将一些数据导入到数据库中进行测试(spring.datasource.data),然后还更改使用的数据库 - 无需复制整个配置并且每次都必须在两个位置更改它。
重要的部分:
@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(locations = "classpath:application-test.properties")
public class TestconfigApplicationTests {
@Value("${my.test.property}")
private String testproperty;
@Test
public void assertValue() {
Assert.assertEquals("foobar", testproperty);
}
}
Run Code Online (Sandbox Code Playgroud)
或者测试包中的配置类:
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
@PropertySource("classpath:application-test.properties")
public class GlobalTestConfig {
}
Run Code Online (Sandbox Code Playgroud)
更新:
答案中的主要建议是使用@ActiveProfile激活“测试”配置文件,这将导致加载“application-test.yaml”。这比 更好@TestPropertySource,但我仍然需要在每个测试类上添加注释。我尝试创建一个元注释 - 它应该可以工作- 所以至少我只有一个自定义注释,我可以在其中捆绑其他设置。但这是行不通的。
完美的解决方案是使用一个配置类全局设置这些设置,而不必在每个测试上添加注释。我仍在寻找该解决方案,或者至少在关闭此问题之前调试元注释。编辑:我创建了一个 Jira 问题:SPR-17531
编辑
好吧,我有点困惑,所以我重新测试了所有不同的组合:
@TestPropertySource(locations = "classpath:application-test.properties") …如何为 if...else 语句编写一个模拟测试用例,其中还包括异常测试,我对此很困惑。UserService 是一个接口
用户工厂.java
public class UserFactory {
@Autowired
private List<UserService> UserList;
private final Map<String, UserService> UserMap = new HashMap<>();
@PostConstruct
public void initUserMap() {
for (final UserService user : UserList) {
UserMap.put(user.getUserId(), user);
}
}
public UserService getUser(String userId) {
final UserService userService = UserMap.get(userlId);
if (null == userService) {
throw new IllegalArgumentException("user are not in the group");
}
return userService;
}
}
Run Code Online (Sandbox Code Playgroud)
用户服务(接口)
public interface UserService{
String getUserName();
String getUserId();
}
Run Code Online (Sandbox Code Playgroud)
这是我的测试,但它不正确......
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest …Run Code Online (Sandbox Code Playgroud) 我想在 spring boot+ JPA 中执行单元测试。为此,我创建了配置文件来为 dataSource、所有 hibernate 属性、entityManagerFactory 和 transactionManager 创建 bean。一切都很完美。表是由模型类创建的。但现在我想通过data.sql文件在数据库的所有表中插入数据进行测试。我将 data.sql 文件保留在 src/main/resources 中,但它没有加载该文件。那么在开始单元测试之前如何在 h2 数据库中加载数据。
这是我的配置文件 -
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.cfg.Environment;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableJpaRepositories(basePackages = "base_package_name")
@EnableTransactionManagement
public class JPAConfig {
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1");
/*dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
dataSource.setUrl("jdbc:hsqldb:mem:testdb");*/
dataSource.setUsername("sa");
dataSource.setPassword("");
return dataSource;
} …Run Code Online (Sandbox Code Playgroud) 我正在尝试创建 Spring Boot 控制器的 MockMvc 测试。我特别不希望启动整个应用程序上下文,因此我将上下文限制为有问题的控制器。但是,测试失败并显示 500,并显示以下日志输出:
2020-03-03 13:04:06.904 WARN 8207 --- [ main] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class main.endpoints.ResponseDto]
Run Code Online (Sandbox Code Playgroud)
看来 Spring Boot 上下文不知道如何找到 Jackson。
这是控制器
@RestController
class MyController {
@GetMapping("/endpoint")
fun endpoint(): ResponseDto {
return ResponseDto(data = "Some data")
}
}
data class ResponseDto(val data: String)
Run Code Online (Sandbox Code Playgroud)
测试如下:
@SpringBootTest(
classes = [MyController::class],
webEnvironment = SpringBootTest.WebEnvironment.MOCK
)
@AutoConfigureMockMvc
internal class MyControllerTest(@Autowired private val mockMvc: MockMvc) {
@Test
fun `should work`() {
mockMvc.perform(MockMvcRequestBuilders.get("/endpoint").accept(MediaType.APPLICATION_JSON))
.andExpect( …Run Code Online (Sandbox Code Playgroud) 拥有一个 Spring Boot 应用程序,使用 Spring Data JPA 和 H2 配置,用于示例/学术目的。
存储库定义为:
public interface PersonaRepository extends CrudRepository<Persona, String> {
}
Run Code Online (Sandbox Code Playgroud)
然后进行以下测试
@ActiveProfiles(profiles={"h2"})
@DataJpaTest
class PersonaRepositorySliceTests {
@Autowired
private PersonaRepository personaRepository;
@Autowired
private TestEntityManager testEntityManager;
@Test
void countTest() {
long count = personaRepository.count();
assertThat(count).isEqualTo(33);
count = testEntityManager.getEntityManager()
.createQuery("SELECT COUNT(*) FROM Persona p")
.getResultList().size();
System.out.println("count: " + count);//prints 1
//assertThat(count).isEqualTo(33);//fails
count = testEntityManager.getEntityManager()
.createNativeQuery("SELECT COUNT(*) FROM persona")
.getResultList().size();
System.out.println("count: " + count);//prints 1
assertThat(count).isEqualTo(33);//fails
}
}
Run Code Online (Sandbox Code Playgroud)
这
long count = personaRepository.count();
assertThat(count).isEqualTo(33);
Run Code Online (Sandbox Code Playgroud)
通过,因此 …
我有一个@SpringBootTest类,它有一个相当复杂的模拟定义设置,带有模拟的返回值。
问题:我可以将@MockBean设置外部化到一个自己的类中,以便我可以在多个类中重用模拟配置(旁注:我不是在这里寻找继承!)。
@SpringBootTest
public class ServiceTest extends DefaultTest {
@Autowired
private ServiceController controller;
@MockBean
private Service1 s1;
@MockBean
private Service2 s2;
@MockBean
private Service3 s3;
//assume more complex mock definitions
@BeforeEach
public void mock() {
when(s1.invoke()).thenReturn(result1);
when(s2.invoke()).thenReturn(result2);
when(s3.invoke()).thenReturn(result3);
}
@Test
public void test() {
//...
}
}
Run Code Online (Sandbox Code Playgroud)
我想相互独立地加载模拟,而不是全局加载我的所有测试。
我编写用@SpringBootTest注释的集成测试。为了运行测试,我将测试资源中的 data.sql 中的数据插入到 H2 数据库中。
\n我遇到的情况是,第一次测试成功运行,经过多次后,出现错误,告诉我,H2 无法在表中插入数据,因为找不到该表。每次启动测试时都会出现不同的原始错误。在同一日志中,我看到在异常发生之前该表已创建,并且其他插入已成功执行。我看到我的 5 个测试中有 4 个是绿色的,一个是红色的。不同的时间可能有不同的测试。
\n重新启动 IDE 可使测试再次成功运行 3-4 次。之后,错误返回。
\n我尝试将 @DirtiesContext() 与我的测试类和测试方法一起使用,但它没有解决问题。
\n我猜测问题的根源可能在于我初始化数据库的方式。对于这两种数据库,我都使用一个 data.sql 文件的引用。我没有找到一种方法将它们分成不同的 *.sql 文件。
\n第二个猜测是在创建表之前就开始插入数据库。我现在通过将所有插入移动到测试代码中来检查这个理论。但我不确定这是否会有所帮助,因为我播种日志是在插入开始之前创建的表。
\n我在每次测试运行之前使用“mvn clean”。
\n我将非常感谢您在解决这个问题方面的建议。
\n我的实体:
\n@Entity\n@Table(name = "entity1", schema = "schema1")\n@Data\n@Builder\n@NoArgsConstructor\n@AllArgsConstructor\npublic class SomeEntityClass extends GenericEntity<Long> { ...}\n\n\n@MappedSuperclass\npublic abstract class GenericEntity<ID extends Serializable> implements Serializable {\n\n @Id\n @GeneratedValue(strategy = GenerationType.IDENTITY)\n @Column\n\n protected ID id;\n\n//getter, setter\n}\n\nRun Code Online (Sandbox Code Playgroud)\n在我的 data.sql 文件中初始化看起来像这样:
\ncreate schema if not exists schema1;\ncreate schema if …Run Code Online (Sandbox Code Playgroud) 为什么使用时缓存会被值填满
@Autowired
ServiceXY serviceXY
@TestConfiguration
static class AppDefCachingTestConfiguration {
@Bean
public ServiceXY ServiceXYMock() {
return mock(ServiceXY.class);
}
}
Run Code Online (Sandbox Code Playgroud)
但不与
@MockBean
ServiceXY serviceXY
Run Code Online (Sandbox Code Playgroud)
使用 @MockBean 时,在访问缓存值时会出现 NullPointerException,如我的测试中所示:
@Autowired
ConcurrentMapCacheManager cmcm;
@Test
void anTest(){
when(serviceXY.methodThatFillsCache(anyString()).thenReturn("ABC");
serviceXY.methodThatFillsCache("TEST1");
cmcm.getCache("Cachename").get("TEST1",String.class).equals("ABC");
...
}
Run Code Online (Sandbox Code Playgroud) mockito spring-bean spring-boot spring-cache spring-boot-test
我试图升级由两个测试片(在我的情况下为@JsonTest和@JdbcTest,中间是脆脆的测试代码)制成的美味三明治,为其添加了spring boot 2.1风味。但似乎并没有太大的成功。我无法使用许多@ ... Test注释测试,因为它们现在各自带有自己的XxxTestContextBootstrapper。当他们都使用相同的SpringBootTestContextBootstrapper时,它可以正常工作。
@RunWith(SpringRunner.class)
@JdbcTest
@JsonTest
public class Test {
@Test
public void test() { System.out.printn("Hello, World !"); }
}
Run Code Online (Sandbox Code Playgroud)
我从BootstrapUtils收到的错误是llegalStateStateException:配置错误:为测试类找到了@BootstrapWith的多个声明
我知道我在这里可能做错了什么,但是有一种简单的方法可以同时加载Json和Jdbc上下文吗?
spring-boot-test ×10
spring-boot ×8
java ×5
h2 ×2
junit ×2
mockito ×2
spring ×2
unit-testing ×2
h2db ×1
jackson ×1
junit5 ×1
kotlin ×1
spring-bean ×1
spring-cache ×1
spring-jdbc ×1