英文:
Using an interface for mocking purposes in unit tests for Java with Spring
问题
我在尝试使用基于Spring的API中模拟接口时遇到了问题。我得到了这个错误:
描述:
构造函数中的Service的参数0需要一个类型为'bm.app.services.DiscountProvider'的bean,但找不到该bean。
操作:
考虑在配置中定义一个类型为'bm.app.services.DiscountProvider'的bean。
而我实在是不明白。我正在将一个接口(DiscountProvider)作为我的服务类(Service)构造函数的参数添加进去,以便于使用Mockito进行测试。
我的Service的开头部分(我认为这是唯一相关的部分)如下所示:
@org.springframework.stereotype.Service
public class Service {
DiscountProvider discountProvider;
public Service(DiscountProvider discountProvider) {
this.discountProvider = discountProvider;
}
接口如下所示:
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Component
public interface DiscountProvider {
BigDecimal getThePriceOfTheProduct();
}
而我的测试类如下所示:
@Component
public class ServiceTests {
Service service;
DiscountProvider discountProvider;
@Test
@DisplayName("应返回比原价高十个百分点的值。")
void shouldReturnValueHigherByTenPercent() {
//给定
Mockito.when(discountProvider.getThePriceOfTheProduct()).thenReturn(new BigDecimal("20.00"));
AdditionalMiniProduct product = new AdditionalMiniProduct(UUID.randomUUID(), new BigDecimal("300.00"), "Yellow Loan");
//当
BigDecimal result = service.increaseByGivenAmount(product.getNetPrice(), discountProvider.getThePriceOfTheProduct());
//那么
assertThat(result).isEqualTo("315.00");
}
@Test
void shouldReturnACorrectRiskLevelValue() {
int months = 18;
assertEquals(5, calculateRiskLevelByNumberOfMonths(months));
}
@Test
void shouldReturnACorrectEnumValueBasedOnNumberOfMonths() {
int months = 26;
assertEquals(RiskLevel.HIGH, giveTheRiskNameBasedOnNumberOfMonths(months));
}
@Test
void shouldReturnAPriceOfAProvidedFinancialProduct() {
BigDecimal productPrice = new BigDecimal(1200);
String productName = "SilverLoan";
assertEquals(productPrice,findAProductPriceByGivenName(productName));
}
@BeforeEach
void setUp() {
service = new Service(discountProvider);
discountProvider = Mockito.mock(DiscountProvider.class);
}
}
现在,我在测试方面相对比较新,所以我确实预计可能会有一些初级错误。问题在于,这是我第一次尝试在我的Spring应用程序中运行更"复杂"的单元测试,而我就是搞不明白。它拒绝承认@Component注释(或者我找到的任何其他注释)。
英文:
I have a problem trying to mock interfaces in my API based on Spring. I am getting this error:
Description:
Parameter 0 of constructor in bm.app.services.Service required a bean of type 'bm.app.services.DiscountProvider' that could not be found.
Action:
Consider defining a bean of type 'bm.app.services.DiscountProvider' in your configuration.
And I just don't understand it. I am adding an interface (DiscountProvider) as a parameter for a constructor of my service class (Service) in order to use Mockito for testing purposes.
The beginning of my Service (I think the only relevant part here) looks like this:
@org.springframework.stereotype.Service
public class Service {
DiscountProvider discountProvider;
public Service(DiscountProvider discountProvider) {
this.discountProvider = discountProvider;
}
The interface looks like this:
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Component
public interface DiscountProvider {
BigDecimal getThePriceOfTheProduct();
}
And my test class looks like that:
@Component
public class ServiceTests {
Service service;
DiscountProvider discountProvider;
@Test
@DisplayName("Should return the value higher by ten percent.")
void shouldReturnValueHigherByTenPercent() {
//given
Mockito.when(discountProvider.getThePriceOfTheProduct()).thenReturn(new BigDecimal("20.00"));
AdditionalMiniProduct product = new AdditionalMiniProduct(UUID.randomUUID(), new BigDecimal("300.00"), "Yellow Loan");
//when
BigDecimal result = service.increaseByGivenAmount(product.getNetPrice(), discountProvider.getThePriceOfTheProduct());
//then
assertThat(result).isEqualTo("315.00");
}
@Test
void shouldReturnACorrectRiskLevelValue() {
int months = 18;
assertEquals(5, calculateRiskLevelByNumberOfMonths(months));
}
@Test
void shouldReturnACorrectEnumValueBasedOnNumberOfMonths() {
int months = 26;
assertEquals(RiskLevel.HIGH, giveTheRiskNameBasedOnNumberOfMonths(months));
}
@Test
void shouldReturnAPriceOfAProvidedFinancialProduct() {
BigDecimal productPrice = new BigDecimal(1200);
String productName = "SilverLoan";
assertEquals(productPrice,findAProductPriceByGivenName(productName));
}
@BeforeEach
void setUp() {
service = new Service(discountProvider);
discountProvider = Mockito.mock(DiscountProvider.class);
}
}
Now, I am fairly new to testing, so I do expect to have made some rookie mistakes. The thing is, that's my first attempt to have more "complex" unit tests run with one of my Spring apps and I just don't get it. It refuses to acknowledge the @Component (or any other I managed to find) annotation.
答案1
得分: 0
如果您正在对 `Service` 类进行单元测试,应该模拟该测试类的所有外部依赖。
假设您正在使用 JUnit 5,可能的测试设置如下:
@ExtendWith(MockitoExtension.class)
public class ServiceTest {
@Mock
private DiscountProvider discountProvider;
@InjectMocks
private Service service;
@Test
@DisplayName("应返回比例增加十个百分点的值。")
void shouldReturnValueHigherByTenPercent() {
//given
Mockito.when(discountProvider.getThePriceOfTheProduct()).thenReturn(new BigDecimal("20.00"));
AdditionalMiniProduct product = new AdditionalMiniProduct(UUID.randomUUID(), new BigDecimal("300.00"), "Yellow Loan");
//when
BigDecimal result = service.increaseByGivenAmount(product.getNetPrice(), discountProvider.getThePriceOfTheProduct());
//then
assertThat(result).isEqualTo("315.00");
}
}
另外,您的测试类不需要使用 `@Component`。这个注解用于您的 _生产_ 代码,用于标记 Spring bean。
英文:
If you are unit testing your Service
class, you should mock all external dependencies of this class under test.
Assuming you are using JUnit 5, a possible test setup can look like the following
@ExtendWith(MockitoExtension.class)
public class ServiceTest {
@Mock
private DiscountProvider discountProvider;
@InjectMocks
private Service service;
@Test
@DisplayName("Should return the value higher by ten percent.")
void shouldReturnValueHigherByTenPercent() {
//given
Mockito.when(discountProvider.getThePriceOfTheProduct()).thenReturn(new BigDecimal("20.00"));
AdditionalMiniProduct product = new AdditionalMiniProduct(UUID.randomUUID(), new BigDecimal("300.00"), "Yellow Loan");
//when
BigDecimal result = service.increaseByGivenAmount(product.getNetPrice(), discountProvider.getThePriceOfTheProduct());
//then
assertThat(result).isEqualTo("315.00");
}
}
In addition, you don't need @Component
for your test classes. This annotation is used for your production code to mark Spring beans.
专注分享java语言的经验与见解,让所有开发者获益!
评论