如何对Spring Boot的MongoRepository进行单元测试?

34
在我的Spring Boot Web应用程序中,我使用MongoDB存储数据。在应用程序中,我使用扩展MongoRepository的接口访问数据库。
如何为这样的存储库类设置单元测试?我想要的是:
  • 启动MongoDB的嵌入式/内存实例
  • 从JSON或XML插入测试数据
  • 使用自动装配的存储库对测试数据执行查询
我尝试使用嵌入式MongoDB,但我无法弄清如何从文件插入测试数据。我还尝试使用NoSQLUnit,但SpringApplicationConfiguration与单元测试配置冲突,导致读取和写入不同的数据库。

你看过 fongo 吗?链接:https://github.com/fakemongo/fongo - Smajl
是的,我目前使用的是NoSQLUnit和Fongo的组合。它似乎可以工作,但是在查询插入的数据时返回了零结果。请参见我的更具体的问题:http://stackoverflow.com/questions/31972146/nosqlunit-mongodb-no-results-after-usingdataset - Johanneke
使用@SpringBootTest和将de.flapdoodle.embed:de.flapdoodle.embed.mongo作为test依赖项,即可创建集成测试。参见https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-mongo-embedded。 - andy
6个回答

9

针对2018年和Spring Boot 2的更新,首先,您可以使用嵌入式数据库进行数据集成测试,根据文档,这使用了DataMongoTest注释。它仅配置了使mongoDB测试成为可能的必要依赖项。

如果您想要进行完整的集成测试,请改为添加AutoConfigureDataMongo注释:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@AutoConfigureDataMongo
public class PriceApiControllerIT {

您的pom.xml应该具有以下依赖项:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>de.flapdoodle.embed</groupId>
        <artifactId>de.flapdoodle.embed.mongo</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

8

只需使用Spring Boot中的@DataMongoTest即可。

@RunWith(SpringRunner.class)
@DataMongoTest
public class FooRepositoryTest {

    @Autowired
    FooRepository fooRepository;

    @Before
    public void setUp() throws Exception {
        fooRepository.save(new Foo());
    }

    @Test
    public void shouldBeNotEmpty() {
        assertThat(fooRepository.findAll()).isNotEmpty();
    }
}

依赖项

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
    <groupId>de.flapdoodle.embed</groupId>
    <artifactId>de.flapdoodle.embed.mongo</artifactId>
    <scope>test</scope>
</dependency>

3

这就是我所做的。

public interface UserRepository extends MongoRepository<Users, Long> {

    public void deleteByUserId(String userId);

    public List<Users> findAllByUserStatus(String userStatus);
}

@Document
public class Users {

    @Id
    private long id;

    @Transient
    public static final String SEQUENCE_NAME = "users_sequence";

    @Indexed
    @NotNull
    private String userId;

    private String firstName;
    private String lastName;
    private String userType;
    private String userStatus;

    @Email
    private String emailId;

    @Size(min = 10, max = 10)
    @NumberFormat
    private String phoneNumber;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getUserType() {
        return userType;
    }

    public void setUserType(String userType) {
        this.userType = userType;
    }

    public String getEmailId() {
        return emailId;
    }

    public void setEmailId(String emailId) {
        this.emailId = emailId;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public static String getSequenceName() {
        return SEQUENCE_NAME;
    }

    public String getUserStatus() {
        return userStatus;
    }

    public void setUserStatus(String userStatus) {
        this.userStatus = userStatus;
    }

}

这里是junit。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MockodsApplication.class)
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerIT {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    private MockMvc mvc;

    @After
    public void tearDown() {

    }

    @Test
    public void test1() {
        Users user = new Users();
        long userId = 1L;
        user.setId(userId);
        user.setFirstName("FirstName");
        user.setLastName("FirstName");
        user.setEmailId("fisrtname.secondname@gmail.com");
        user.setPhoneNumber("1234567890");

        assertEquals(user, userRepository.save(user));
    }

    @Test
    public void test2() {
        List<Users> persistedUser = userRepository.findAll();
        assertEquals("fisrtname.secondname@gmail.com", persistedUser.get(0).getEmailId());
    }
}

这个链接帮助我实现了https://dzone.com/articles/spring-integration-tests


2

我遇到了同样的问题,我们使用了一个单独的MongoConfiguration类来为我们的测试指定特定的配置。

您可以使用EmbeddedMongoBuilder创建一个嵌入式mongo实例,就像这样:

import com.mongodb.Mongo;
import cz.jirutka.spring.embedmongo.EmbeddedMongoBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.net.ServerSocket;

@Configuration
public class MongoConfiguration {

    @Bean
    public Mongo mongo() throws IOException {
        System.setProperty("DB.TRACE","true");
        return new EmbeddedMongoBuilder()
            .version("2.13.1")
            .bindIp("127.0.0.1")
            .port(allocateRandomPort())
            .build();
    }
}

然后在您的测试类中,使用 @Import 注释指定您想要使用该特定配置:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@Import(MongoConfiguration.class)

希望这能帮到你。

1

请查看https://mongoUnit.org

从其文档中可以了解到:

这是一个为使用MongoDB进行持久化的Spring Boot应用程序提供数据驱动集成测试框架。该框架使开发人员能够相对轻松地测试数据访问逻辑。


0

首先,请确保您已将以下Spring Boot父项目添加到您的项目中:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.2.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
</parent>

自从我们添加了Spring Boot Parent,我们可以添加所需的依赖项而无需指定它们的版本:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

spring-boot-starter-data-mongodb 将启用 Spring 对 MongoDB 的支持。
<dependency>
    <groupId>de.flapdoodle.embed</groupId>
    <artifactId>de.flapdoodle.embed.mongo</artifactId>
    <scope>test</scope>
</dependency>

de.flapdoodle.embed.mongo 提供了嵌入式 MongoDB,用于集成测试。
添加 de.flapdoodle.embed.mongo 依赖后,Spring Boot 在运行测试时会自动尝试下载和启动嵌入式 MongoDB。以下代码片段展示了您如何手动配置嵌入式 MongoDB 实例。
class EmbeddedMongoDbIntegrationTest {
    private MongodExecutable mongodExecutable;
    private MongoTemplate mongoTemplate;

    @After
    void clean() {
        mongodExecutable.stop();
    }

    @Before
    void setup() throws Exception {
        String ip = "localhost";
        int port = 27017;

        IMongodConfig mongodConfig = new MongodConfigBuilder().version(Version.Main.PRODUCTION)
            .net(new Net(ip, port, Network.localhostIsIPv6()))
            .build();

        MongodStarter starter = MongodStarter.getDefaultInstance();
        mongodExecutable = starter.prepare(mongodConfig);
        mongodExecutable.start();
        mongoTemplate = new MongoTemplate(new MongoClient(ip, port), "test");
    }

    @Test
    void test() throws Exception {
        // given
        DBObject objectToSave = BasicDBObjectBuilder.start()
            .add("key", "value")
            .get();

        // when
        mongoTemplate.save(objectToSave, "collection");

        // then
        assertThat(mongoTemplate.findAll(DBObject.class, "collection")).extracting("key")
            .containsOnly("value");
    }
}

请注意,我们可以快速创建MongoTemplate bean,并配置它以使用我们手动配置的嵌入式数据库,并在Spring容器中注册它,这样您的mongo repository也将开始利用这个mongoTemplate。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接