我使用 akka 框架及其 Java API 和mockito + Testkit 来对 actor 进行单元测试
这是 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) 失败。这个方法已经被 mock 了,它是否应该跳过执行并只返回when语句所说的应该返回的内容?
这是因为我正在实例化 KubeNamspace 的新对象以及 KubeDeployment,因为联系人用于模拟?
最佳答案
您实际上并没有在测试中 mock 任何内容。您正在创建模拟对象,但它们没有被注入(inject)到被测试的代码中。您的参与者正在响应消息时执行以下代码:
KubeNamespace kubeNamespace = new KubeNamespace();
KubeDeployment kubeDeployment = new KubeDeployment();
这会创建新的未模拟对象,这些对象将按编码运行它们的过程 - 并且通常会导致 NPE,因为它们没有依赖的外部依赖项。
如果您想模拟以这种方式创建的对象,您要么必须重构代码以将它们的创建提取到可模拟工厂类中,要么使用更具侵入性的模拟库,例如 PowerMock或jMockit .
工厂模拟示例
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...
}
}
}
关于java - Mockito 与 akka Actor ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49497065/