我正在使用akka框架及其Java API和mockito + Testkit来对actor进行单元测试
这是演员
public class K8sDeploymentCreator extends AbstractActor {
private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
@Override
public Receive createReceive() {
return receiveBuilder().match(createK8sDeployment.class, msg -> {
KubeNamespace kubenamespace = new KubeNamespace();
KubeDeployment kubeDeployment = new KubeDeployment();
Namespace namespace = kubenamespace.createNamespace(msg.kubeClient, msg.service);
Deployment deployment = kubeDeployment.createDeployment(msg.service, msg.kubeClient, namespace);
log.info("sending complete depl msg");
getSender().tell(new K8sDeploymentComplete(deployment), getSelf());
})
.matchAny(o -> log.info("received unknown message")).build();
}
}
这是测试类
public class K8sDeploymentCreatorTest extends JUnitSuite {
static ActorSystem system;
@Before
public void setup() {
system = ActorSystem.create();
KubeDeployment mockKubeDeployment = mock(KubeDeployment.class);
KubeNamespace mockKubeNamespace = mock(KubeNamespace.class);
Deployment deployment = Mockito.mock(Deployment.class);
Namespace namespace = Mockito.mock(Namespace.class);
KubernetesClient kubeClient = Mockito.mock(KubernetesClient.class);
Service serviceTodeploy = new Service("group","artifact","version");
DeployEnvironment deployEnvironment = new DeployEnvironment();
deployEnvironment.setName("K8sDeploymentCreatorTest");
serviceTodeploy.setDeployEnvironment(deployEnvironment);
when(mockKubeNamespace.createNamespace(kubeClient, serviceTodeploy)).thenReturn(namespace);
when(mockKubeDeployment.createDeployment(serviceTodeploy, kubeClient, namespace)).thenReturn(deployment);
}
@AfterClass
public static void teardown() {
TestKit.shutdownActorSystem(system);
system = null;
}
@Test
public void testK8sDeployment() {
new TestKit(system) {
{
final Props props = Props.create(K8sDeploymentCreator.class);
final ActorRef underTest = system.actorOf(props);
KubeDeployment mockKubeDeployment = mock(KubeDeployment.class);
KubeNamespace mockKubeNamespace = mock(KubeNamespace.class);
Deployment deployment = Mockito.mock(Deployment.class);
Namespace namespace = Mockito.mock(Namespace.class);
KubernetesClient kubeClient = Mockito.mock(KubernetesClient.class);
DeployEnvironment deployEnvironment = new DeployEnvironment();
deployEnvironment.setName("K8sDeploymentCreatorTest");
Service serviceTodeploy = new Service("group","artifact","version");
serviceTodeploy.setDeployEnvironment(deployEnvironment);
createK8sDeployment msg = new createK8sDeployment(serviceTodeploy, kubeClient);
underTest.tell(msg, getRef());
expectMsg(K8sDeploymentComplete)
}
};
}
}
尝试在createNamespace()中执行代码时,NPE(NullPointerException)失败。这个方法已被模拟,如果它跳过执行并且只返回when语句应该返回的任何内容?
这是因为我正在实例化KubeNamspace和KubeDeployment的新目标,其中联系人是针对模拟的吗?
答案 0 :(得分:1)
你实际上并没有在测试中嘲笑任何东西。您正在创建模拟对象,但它们没有被注入到测试代码中。您的actor在响应消息时正在执行以下代码:
KubeNamespace kubeNamespace = new KubeNamespace();
KubeDeployment kubeDeployment = new KubeDeployment();
这会创建新的未经模拟的对象,这些对象将按编码方式运行 - 并且通常会导致NPE,因为它们没有依赖它们的外部依赖关系。
如果要模拟以这种方式创建的对象,则必须重构代码以将其创建提取到可模拟的工厂类中,或者使用更具侵入性的模拟库,例如PowerMock或{{3 }}
class KubeFactory {
public KubeNamespace makeNamespace() {
return new KubeNamespace();
}
public KubeDeployment makeDeployment() {
return new KubeDeployment();
}
}
public class K8sDeploymentCreator extends AbstractActor {
private final KubeFactory factory;
K8sDeploymentCreator() {
this(new KubeFactory());
}
// This constructor allows you to override the factory used for testing
K8sDeploymentCreator(KubeFactory factory) {
this.factory = factory;
}
@Override
public Receive createReceive() {
return receiveBuilder().match(createK8sDeployment.class, msg -> {
KubeNamespace kubenamespace = factory.makeNamespace();
KubeDeployment kubeDeployment = factory.makeDeployment();
// rest is as before...
});
}
}
然后在您的测试类中创建一个测试KubeFactory
,它返回您正在测试的类的模拟实例:
@Test
public void testK8sDeployment() {
new TestKit(system) {
{
final KubeFactory mockFactory = mock(KubeFactory.class);
when(mockFactory.makeNamespace()).thenReturn(mockKubeNamespace);
when(mockFactory.makeDeployment()).thenReturn(mockKubeDeployment);
final Props props = Props.create(K8sDeploymentCreator.class, mockFactory);
final ActorRef underTest = system.actorOf(props);
// and so on...
}
}
}