java 正确测试 Spring 服务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44853144/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 08:22:39  来源:igfitidea点击:

Correctly testing a Spring service

javaspringhibernatejunitspring-ws

提问by Darrel Holt

The following test fails with a NullPointerExceptionon the line usersRepo.save(user);. I believe it's because when the test goes into the performProvision()function the usersRepoobject is null.

以下测试失败,并NullPointerException显示为usersRepo.save(user);。我相信这是因为当测试进入performProvision()函数时,usersRepo对象是null.

However, when the web service is actually running and the endpoint for my controller is hit, everything works fine and the database is updated.

但是,当 Web 服务实际运行并且我的控制器的端点被命中时,一切正常并且数据库被更新。

Any idea why the test fails? My idea was that PAutoProvisionreferences the real database, whereas it should be dealing with the in-memory database so maybe there is some sort of conflict? I have also seen a lot of different examples with annotations set up differently, so I suppose that could be a problem too.

知道为什么测试失败吗?我的想法是PAutoProvision引用真实的数据库,而它应该处理内存数据库,所以可能存在某种冲突?我也看到了很多不同的例子,注释设置不同,所以我想这也可能是一个问题。

UsersRepo extends JpaRepository where PAutoProvision is a SQL table entity.

UsersRepo 扩展了 JpaRepository,其中 PAutoProvision 是一个 SQL 表实体。

If this isn't enough information, I can provide the UsersRepo, PAutoProvision, and ProvisionControllerclasses if necessary.

如果没有足够的信息,我可以提供的UsersRepoPAutoProvision以及ProvisionController如果必要的类。

The Service:

服务:

@Service
public class ProvisionService {

    @Autowired
    private UsersRepo usersRepo;


    public String performProvision(UserData userData) {
        try {
            PAutoProvision user = new PAutoProvision(userData);
            usersRepo.save(user);  // OOTB CRUD repository functionality of springData to update/insert record data
            return String.format("Success: User %s has been added to the database", userData.getUserId());
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.toString());
            System.out.println("\n\n Cannot perform the provisioning of the user " + userData.getUserId() + ": \n" + e.toString() + "\n\n");
        }

        return "problem";
    }
}

The Test:

考试:

@RunWith(SpringRunner.class)
public class ProvisionServiceTest {

    private ProvisionService provisionService;

    @MockBean
    private UsersRepo usersRepo;

    @Before
    public void setUp(){
        provisionService = new ProvisionService();
    }

     @Test
    public void performProvision_shouldPass() {
        UserData userData = new UserData("userid", 30, 1, "spot", 1);
        try {
            String result = provisionService.performProvision(userData);
            assertThat(result, is(equalTo("Success: User userid has been added to the database")));
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.toString());
        }
    }
}

EDIT 1:

编辑 1:

Adding @Autowiredand removing setUp()method results in the following:

添加@Autowired和删除setUp()方法的结果如下:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.autoprovision.ProvisionServiceTest': Unsatisfied dependency expressed through field 'provisionService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.autoprovision.ProvisionService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.autoprovision.ProvisionServiceTest': Unsatisfied dependency expressed through field 'provisionService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.autoprovision.ProvisionService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

回答by iBiber

As JB Nizet already stated, the UserRepomock is not injected into the provisionService instance, because the provisionService instance is created in the setUp method with new.

正如 JB Nizet 已经说过的,UserRepo模拟没有被注入到 provisionService 实例中,因为 provisionService 实例是在 setUp 方法中使用new.

Your test should look like this:

您的测试应如下所示:

@RunWith(SpringRunner.class)
public class ProvisionServiceTest {
    @Autowired // let Spring instantiate the instance to test
    private ProvisionService provisionService;

    @MockBean
    private UsersRepo usersRepo;

    @Test
    public void performProvision_shouldPass() {
        UserData userData = new UserData("userid", 30, 1, "spot", 1);

        String result = provisionService.performProvision(userData);
        assertThat(result, is(equalTo("Success: User userid has been added to the database")));
    }
}

回答by robin850

The given answer seems useful but just in case it can help someone, testing service is not so obvious in Spring (IMHO). The SpyBeanannotation turns out to be really handy:

给定的答案似乎很有用,但以防万一它可以帮助某人,Spring 中的测试服务并不那么明显(恕我直言)。该SpyBean注释被证明是非常方便的:

@RunWith(SpringRunner.class)
public class ProvisionServiceTest {
    @SpyBean
    private ProvisionService provisionService;
}

Source : Spring Boot Reference - Testing

来源:Spring Boot 参考 - 测试