Spring引导中的单元测试最佳实践,用于在服务级别进行模拟

时间:2018-02-15 09:14:29

标签: spring unit-testing spring-boot mocking mockito

我们有一个单元测试,我们正在测试兑换促销代码。 我们需要检查数据库中是否存在两个参数:Entity& User

在您将看到的代码中,

  1. 我们创建了UserEntity
  2. 的实例
  3. 插入db(使用@Repository)
  4. 创建DTO ..也是
  5. 因为RedeemService会调用UserEntity服务来检查这些服务是否存在。

    我觉得我们不应该做这一切,而应该能够模拟(用户和实体服务)

    以下是测试:

    @Test 
        public void redeemPromoCodeTestValid() throws Exception {
    
            String userId = "OOUser";
            String fleetId = "F0001";
            String promoCodeId = "AFTER_CHRIS";
    
            User user = new User();
            user.setId(userId);
            user.setFleetId(fleetId);
            user.setUserName("OOabcdefg");
            userRepository.save(user);
    
            EntityX entity = new EntityX(); //EntityX, because Entity is a reserved keyword..
            entityRepository.save(entity);
            String entityId = entityRepository.findAll().get(0).getId();
    
            PromoCode promoCode = createPromoCode(promoCodeId);
            promoCodeRepository.save(promoCode);
    
            RedeemDTO add = new RedeemDTO();
            add.setUserId(userId);
            add.setEntityId(entityId);
            String jsonString = this.asJsonString(add);
            MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.put("/billing/fleets/"+ fleetId + "/promoCodes/redeem/" + promoCodeId).content(jsonString).contentType(CONTENT_TYPE);
    
            mockMvcPromocode.perform(requestBuilder).andDo(print()).andExpect(status().isOk());
    
            List<Wallet> find = walletService.findWalletByEntityId(entityId);
            assertThat(find.size()).isEqualTo(1);
        }
    

    我是Spring boot和单元测试模拟的新手,因此非常感谢任何建议。

    感谢。

1 个答案:

答案 0 :(得分:3)

无论对单词的定义有何不同,都有测试仅测试一个类的代码(单元测试),测试Spring集成和http处理(集成测试)的测试,以及测试整个应用程序的测试结束 - 结束(端到端测试)。目前尚不清楚您想要编写哪种测试。

如果要编写单元测试,则需要确定要测试的单元。如果要测试控制器,只需在不使用MockHttpServletRequestBuilder和SpringRunner的情况下测试Java类。

任何Spring类也是一个普通的Java类,您可以像测试任何其他类一样对它们进行单元测试。但是,如果使用构造函数注入,它变得最简单:

@Service
class FooService {

    private final FooBean foo;

    @Autowired
    public FooService(FooBean foo) {
        this.foo = foo;
    }
}

public class FooServiceTest {

    @Test
    public void testFooService() {
        fooMock = mock(FooBean.class); // use Mockito or EasyMock, or real FooBean
        FooService fooService = new FooService(fooMock);
        // ...
    }
}

如果要为控制器编写集成测试,请使用MockHttpServletRequestBuilder并模拟服务层。

为此,请使用以下内容:

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {ControllerTestConfig.class})
@WebAppConfiguration
public class ControllerTest {
    ...
}

@Configuration
public class ControllerTestConfig {
    @Bean
    public UserService userServiceMock() {
        ...
    }
}

对于端到端测试,不使用模拟,但可能使用单独的Spring配置文件连接到测试后端资源/内存数据库。