模拟具有许多依赖项的嵌套服务 类
Mocking nested service classes with many dependencies
我有一堆服务 classes,它们看起来都很像这个或类似的。
@Service
public class ServiceA {
private RepositoryA repA;
private RepositoryB repB;
private DependencyC depC;
private DependencyD depD;
private ServiceB serviceB;
@Autowired
public ServiceA(RepositoryA repA, RepositoryB repB, DependencyC depC, DependencyD depD, ServiceB serviceB) {
this.repA = repA;
....
}
}
现在我想在我的测试 classes 中使用这些服务而无需启动 Spring。如果我在应用程序上下文中使用 beans,测试将花费太长时间。我想模拟服务 classes,但由于嵌套结构很深,我不知道该怎么做。简单的方法是模拟 ServiceA 使用的所有存储库、依赖项和服务,然后自己将它们注入到测试中 class 但这似乎不对,因为我必须对 ServiceB 做同样的事情。
对偶选择:
- 也模拟
ServiceB
- 按照您的描述进行操作,因为无论如何您都会这样做,以便为
ServiceB
编写测试,这样您就可以重用该工作
- 构建一个充满模拟的替代Spring上下文并将其用于测试
我通常选择 2。它是不纯的,因为 ServiceA
的正确性取决于 ServiceB
的正确性,但它较少测试编写、管理和理解的代码。
你可以为此使用 mockito,那么你的代码将与此类似
@RunWith(MockitoJUnitRunner.Silent.class)
public class ServiceATest {
@Mock
RepositoryA repA;
@Mock
RepositoryB repB;
@Mock
DependencyC depC;
@Mock
DependencyD depD;
@Mock
ServiceB serviceB;
@InjectMocks
ServiceA serviceA;
}
然后,当你需要在你的测试中使用模拟时,你模拟你模拟的方法类,例如:
@Test
public void someTest() {
...
when(repA.repMethod()).thenReturn(new SomeObject());
SomeObject mockedObject = serviceA.serviceMethod(); // if serviceMethod call repMethod, you will get the object which you passed in youк mock method call
...
}
public class ServiceATest {
private RepositoryA repA;
private RepositoryB repB;
private DependencyC depC;
private DependencyD depD;
private ServiceB serviceB;
@Before
public void init() {
this.repB = mock(RepositoryA.class);
.....
// mock all repositories you need.
this.serveceB = new ServiceB(repoB,...);
//then use contructor method to instantiate serviceB. Also do same with
//serviceB
this.serviceA = new ServiceA(repA, repB,depC, depD, serviceB)
}
//Write the tests like that
@Test
public void saveanything_shouldBeCorect() {
when(repoA.save()any()).thenReturn(mySavedMock);
MyVariable resp = serviceA.save(myMock);
// them assert your resp.
}
}
重要的是仅在已移动到 init 方法的存储库中使用 mockito 方法“when (rep.anython (any ()))。
我有一堆服务 classes,它们看起来都很像这个或类似的。
@Service
public class ServiceA {
private RepositoryA repA;
private RepositoryB repB;
private DependencyC depC;
private DependencyD depD;
private ServiceB serviceB;
@Autowired
public ServiceA(RepositoryA repA, RepositoryB repB, DependencyC depC, DependencyD depD, ServiceB serviceB) {
this.repA = repA;
....
}
}
现在我想在我的测试 classes 中使用这些服务而无需启动 Spring。如果我在应用程序上下文中使用 beans,测试将花费太长时间。我想模拟服务 classes,但由于嵌套结构很深,我不知道该怎么做。简单的方法是模拟 ServiceA 使用的所有存储库、依赖项和服务,然后自己将它们注入到测试中 class 但这似乎不对,因为我必须对 ServiceB 做同样的事情。
对偶选择:
- 也模拟
ServiceB
- 按照您的描述进行操作,因为无论如何您都会这样做,以便为
ServiceB
编写测试,这样您就可以重用该工作 - 构建一个充满模拟的替代Spring上下文并将其用于测试
我通常选择 2。它是不纯的,因为 ServiceA
的正确性取决于 ServiceB
的正确性,但它较少测试编写、管理和理解的代码。
你可以为此使用 mockito,那么你的代码将与此类似
@RunWith(MockitoJUnitRunner.Silent.class)
public class ServiceATest {
@Mock
RepositoryA repA;
@Mock
RepositoryB repB;
@Mock
DependencyC depC;
@Mock
DependencyD depD;
@Mock
ServiceB serviceB;
@InjectMocks
ServiceA serviceA;
}
然后,当你需要在你的测试中使用模拟时,你模拟你模拟的方法类,例如:
@Test
public void someTest() {
...
when(repA.repMethod()).thenReturn(new SomeObject());
SomeObject mockedObject = serviceA.serviceMethod(); // if serviceMethod call repMethod, you will get the object which you passed in youк mock method call
...
}
public class ServiceATest {
private RepositoryA repA;
private RepositoryB repB;
private DependencyC depC;
private DependencyD depD;
private ServiceB serviceB;
@Before
public void init() {
this.repB = mock(RepositoryA.class);
.....
// mock all repositories you need.
this.serveceB = new ServiceB(repoB,...);
//then use contructor method to instantiate serviceB. Also do same with
//serviceB
this.serviceA = new ServiceA(repA, repB,depC, depD, serviceB)
}
//Write the tests like that
@Test
public void saveanything_shouldBeCorect() {
when(repoA.save()any()).thenReturn(mySavedMock);
MyVariable resp = serviceA.save(myMock);
// them assert your resp.
}
}
重要的是仅在已移动到 init 方法的存储库中使用 mockito 方法“when (rep.anython (any ()))。