【问题标题】:How to inject only one mock inside Service class with normal instantiation to other instances?如何在 Service 类中只注入一个模拟并正常实例化到其他实例?
【发布时间】:2020-10-09 05:20:28
【问题描述】:

假设我已经实现了下一个服务类:

@Service
@RequiredArgsConstructor
@Transactional
public class ItemService {

    private final ItemRepository itemRepository;
    private final ItemCreatorFactory itemCreatorFactory;
    private final CommonClient commonClient;
    private final HelperService helperService;
    private final PrivilegeUtil privilegeUtil;

    public void addItem() {
        //How to only mock this in tests and other defaults to normal Autowired injection
        if(!privilegeUtil.isAdmin("bla bla")) {
             Throw new InvalidOperationException("Only super admin can insert data.");
        }
        helperService.doSomeRealLogic();
        commonClient.callAnotherExternalAPI();
        itemRepository.save(myObject);
    }
    // other methods
}

我需要测试在数据库中插入新项目,但在此之前我正在做一些额外的逻辑,如果它没问题,我可以安全地插入数据库中。

现在我需要使用 mockito,所以我只模拟 privilegeUtil 类,但我需要 ItemService 类中的所有其他实例正常自动装配而不模拟它。

所以我去参加下一堂考试:

@RunWith(SpringRunner.class)
public class ItemTests {

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    @InjectMocks//Only mocks privilegeUtil but other instances is all null :(
    private ItemService itemService;//So how i get autowired item service instance but only mock privilegeUtil instance inside it and all other instances go for normal instantiation ???

    @Mock
    private PrivilegeUtil privilegeUtil;

    @Test
    public void testAddNewItem() {
        String email = "super@mail.com";

        Mockito.when(privilegeUtil.isSuperAdmin(email)).thenReturn(true);
        
        //Here i need to test adding item normally
        //But only skip checking isSuperAdmin part inside addItem method
        itemService.addItem(itemRequest, email);
    }

}

那么我如何获得自动装配的项目服务实例,但只在其中模拟 privilegeUtil 实例,而所有其他实例都进行正常实例化???

这可能吗?如果不是这样,您可以提出什么建议?

【问题讨论】:

    标签: spring-boot mockito powermockito spring-boot-test


    【解决方案1】:

    是的,这是可能的。正如您所提到的,您测试了一些与数据库相关的逻辑,我想使用 @DataJpaTest 让 Spring 为您创建一个包含所有 JPA/数据库相关组件的 sliced context 是有意义的。

    然后您就可以在测试中自动装配您的存储库了。

    剩下的就是使用例如手动创建所有其他 normal bean。 @TestConfiguration。您要模拟的那些类,用@MockBean 注释它们,以便Spring 将模拟版本放入切片上下文中。

    @RunWith(SpringRunner.class)
    @DataJpaTest
    public class ItemTests {
    
      @TestConfiguration
      static class TestConfig {
    
        @Bean
        public ItemCreatorFactory itemCreatorFactory() {
          return new ItemCreatorFactory();
        }
    
       // .. manually create all other beans
    
      }
    
      @Autowired
      private ItemRepository itemRepository;
    
      @Autowired
      private ItemCreatorFactory itemCreatorFactory;
    
      @Autowired
      private CommonClient commonClient;
    
      @Autowired
      private HelperService helperService;
    
      @MockBean
      private PrivilegeUtil privilegeUtil;
    
      @Before
      public void setUp() throws Exception {
         this.itemService = new ItemService(itemRepository, itemCreatorFactory, commonClient, helperService, mockedPrivilegeUtil);
      }
    
      @Test
      public void testAddNewItem() {
          String email = "super@mail.com";
          
          Mockito.when(privilegeUtil.isSuperAdmin(email)).thenReturn(true);
        
          itemService.addItem(itemRequest, email);
      }
    
    }
    

    ...然后您终于可以手动实例化您的ItemService 并将您的所有实例传递给构造函数。

    【讨论】:

      猜你喜欢
      • 2018-07-30
      • 2019-09-24
      • 1970-01-01
      • 2013-01-14
      • 1970-01-01
      • 2012-02-26
      • 2012-11-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多