Mokito与akka演员

时间:2018-03-26 17:15:57

标签: java mocking mockito akka

我正在使用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的新目标,其中联系人是针对模拟的吗?

1 个答案:

答案 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...
    }
  }
}