【问题标题】:How to use Dependency Injection with Spring Boot Unit Testing?如何在 Spring Boot 单元测试中使用依赖注入?
【发布时间】:2020-12-11 07:37:58
【问题描述】:

是否可以在使用 Spring Boot 的单元测试中使用依赖注入?对于集成测试@SpringBootTest,启动整个应用程序上下文和容器服务。但是是否可以在单元测试粒度上启用依赖注入功能?

这是示例代码

@ExtendWith(SpringExtension.class)
public class MyServiceTest {
    
    @MockBean
    private MyRepository repo;
    
    @Autowired
    private MyService service; // <-- this is null
    
    @Test
    void getData() {
        MyEntity e1 = new MyEntity("hello");
        MyEntity e2 = new MyEntity("world");
        
        Mockito.when(repo.findAll()).thenReturn(Arrays.asList(e1, e2));
        
        List<String> data = service.getData();
        
        assertEquals(2, data.size());
    }
}

@Service
public class MyService {
    
    private final MyRepository repo; // <-- this is null
    
    public MyService(MyRepository repo) {
        this.repo = repo;
    }
    
    public List<String> getData() {
        return repo.findAll().stream()
                .map(MyEntity::getData)
                .collect(Collectors.toList());
    }
}

或者我应该将 SUT(服务类)作为 POJO 管理并手动注入模拟的依赖项?我想保持快速测试,但尽量减少样板代码。

【问题讨论】:

  • 如果你想要一个单元测试不要使用依赖注入如果你想要一个集成测试或系统测试使用注入。在这里,除了复杂性和缓慢的测试,它不会增加任何东西。只需将@Autowired 替换为@InjectMocks 并将@MockBean 替换为@Mock 并使用正确的mockito 跑步者而不是弹簧扩展。或者只是手动创建服务的模拟和实例(甚至更快)。

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


【解决方案1】:

正如 cmets 中提到的 @M.Deinum,单元测试不应该使用依赖注入。使用 Mockito(和 Junit5)模拟 MyRepository 并注入 MyService

@ExtendWith(MockitoExtension.class)
public class MyServiceTest {

    @InjectMocks
    private MyService service;

    @Mock
    private MyRepository repo;

    @Test
    void getData() {
        MyEntity e1 = new MyEntity("hello");
        MyEntity e2 = new MyEntity("world");

        Mockito.when(repo.findAll()).thenReturn(Arrays.asList(e1, e2));

        List<String> data = service.getData();

        assertEquals(2, data.size());
    }
}

如果您想测试存储库,请使用@DataJpaTest。来自docs

使用此注解将禁用完全自动配置,取而代之的是 仅应用与 JPA 测试相关的配置。

@DataJpaTest
public class MyRepositorTest {

    @Autowired
    // This is injected by @DataJpaTest as in-memory database
    private MyRepository repo;

    @Test
    void testCount() {
        repo.save(new MyEntity("hello"));
        repo.save(new MyEntity("world"));

        assertEquals(2, repo.count());
    }
}

总之,建议的方法是使用Mockito(或类似库)测试服务层模拟存储库层,并使用@DataJpaTest 测试存储库层。

【讨论】:

    【解决方案2】:

    您还没有为MyRepository添加服务中的@Autowired

    服务类

    @Service
    public class MyService {
        
        private final MyRepository repo; // <-- this is null
        
        @Autowired
        public MyService(MyRepository repo) {
            this.repo = repo;
        }
        
        public List<String> getData() {
            return repo.findAll().stream()
                    .map(MyEntity::getData)
                    .collect(Collectors.toList());
        }
    }
    

    服务测试类

    @ExtendWith(MockitoExtension.class)
    public class MyServiceTest {
        
        @Mock
        private MyRepository repo;
        
        @InjectMocks
        private MyService service;
        
        @Test
        void getData() {
            MyEntity e1 = new MyEntity("hello");
            MyEntity e2 = new MyEntity("world");
            
            Mockito.when(repo.findAll()).thenReturn(Arrays.asList(e1, e2));
            
            List<String> data = service.getData();
            
            assertEquals(2, data.size());
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-05-21
      • 2021-06-19
      • 1970-01-01
      • 2020-01-09
      • 1970-01-01
      • 1970-01-01
      • 2017-04-01
      相关资源
      最近更新 更多