【问题标题】:Mock actorRef.tell inside an Actor class在 Actor 类中模拟 actorRef.tell
【发布时间】:2017-06-21 13:44:20
【问题描述】:

我有一个演员类EmployeeActor,在该演员内部,使用payrollRunActor.tell() 解雇了其他演员。我需要为EmployeeActor.java 编写一个JUnit 测试,但我不想触发payrollRunActor.tell(),这意味着我想模拟它。

有办法吗?我尝试了很多,但真正的payrollRunActor 被解雇了。 这是我的EmployeeActor 类的实际代码。

包 com.test.periodic.actors;

import java.util.List;

import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.test.avs.domain.boundedcontext.Employee;
import com.test.avs.domain.boundedcontext.PayrollRun;
import com.test.entity.BusinessDTO;
import com.test.periodic.actors.aggregrators.EmployeeAggregator;

import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.routing.RoundRobinPool;

public class EmployeeActor extends AbstractActor {
    private static final Logger logger = LoggerFactory.getLogger(EmployeeActor.class);
    private boolean rollup;

    public static Props props() {
        return Props.create(EmployeeActorTest.class);
    }

    private List<PayrollRun> payrollRuns;
    private String instanceId;
    private String employeeAggregatorId;
    private Employee employee;
    private ActorRef organizationAggregatorActor;
    private List<BusinessDTO> businessDTOs;

    final ActorSystem payrollRunSystem = ActorSystem.create("payrollRun");

    ActorRef employeeAggregator;

    public EmployeeActor(ActorRef organizationAggregatorActor, List<PayrollRun> payrollRuns,
            Employee employee, List<BusinessDTO> businessDTOs, boolean rollup) {
        this.payrollRuns = payrollRuns;
        this.employee = employee;
        this.organizationAggregatorActor = organizationAggregatorActor;
        this.businessDTOs = businessDTOs;
        this.rollup = rollup;
    }

    @Override
    public void preStart() throws Exception {
        instanceId = RandomStringUtils.randomAlphanumeric(6);
        employeeAggregatorId = "employeeAggregator-" + instanceId;
        employeeAggregator = getContext().system().actorOf(
                Props.create(EmployeeAggregator.class, organizationAggregatorActor, employee),
                employeeAggregatorId);
        super.preStart();
    }

    @Override
    public Receive createReceive() {
        return receiveBuilder().match(Employee.class, employee -> {

            if (rollup) {
                logger.info("Rollingup business entities.");
                employeeAggregator.tell(employee, getSelf());
            } else {
                ActorRef payrollRunActor = payrollRunSystem.actorOf(new RoundRobinPool(payrollRuns.size())
                        .props(Props.create(PayrollRunActor.class, employeeAggregator, employee, businessDTOs)));
                for (PayrollRun payrollRun : payrollRuns) {
                    **payrollRunActor.tell(payrollRun, getSelf());**
                }
            }


        }).match(PayrollRun.class, maxPaydatePayrollRun -> {
            ActorRef payrollRunActor = payrollRunSystem
                    .actorOf(Props.create(PayrollRunActor.class, employeeAggregator, employee, businessDTOs));
            **payrollRunActor.tell(maxPaydatePayrollRun, getSelf());**
        }).build();
    }
}

【问题讨论】:

  • 您可能根本不想这样做。使用Probe 替换payrollRunActor。嘲笑这可能是一条非常痛苦的道路。

标签: java unit-testing akka mockito powermock


【解决方案1】:

首先,您必须模拟在创建被测类期间调用的静态方法调用。然后让它返回一个间谍对象并模拟你想要避免调用的方法:

@RunWith(PowerMockRunner.class)
@PrepareForTest(ActorSystem.class)
public void TestClass{

     @Test
     public void test(){
          // Arrange
          PowerMockito.mockStatic(ActorSystem.class);
          ActorSystem actorSystemMock = Mockito.mock(ActorSystem.class);
          Actor actorSpy = Mockito.spy(new Actor());

          Mockito.when(ActorSystem.create("payrollRun")).thenReturn(actorSystemSpy);

          Mockito.when(actorSystemMock.actorOf(any(RoundRobinPool.class)))
            .thenReturn(actorSpy);     

          Mockito.doNothing().when(actorSpy)
            .tell(Mockito.any(PayrollRun.class), Mockito.any(Self.class));

          EmployeeActor employeeActor = new EmployeeActor(); 

          // Act and assert...
          employeeActor.createReceive();
     }
}

请记住,actorSystemSpy 的所有其他方法都将被调用并将真正实现。如果您想模拟所有这些,请使用Mockito.mock 而不是 spy。

【讨论】:

  • 我对下面的代码有疑问,tell 方法在 when(actorSystemSpy) 上不可用,因为 actorSystemSpy 是一个 ActorSystem,而不是 Actor。那是对的吗? Mockito.doNothing().when(actorSystemSpy).tell(Mockito.any(PayrollRun.class), Mockito.any(Self.class));
  • 模拟tell()方法时,报错java.lang.ClassCastException: akka.actor.ActorRef$$EnhancerByMockitoWithCGLIB$$ef59ca36 cannot be cast to akka.actor.ScalaActorRef
  • 出现错误。确保使用 ActorSystem actorSystemMock = Mockito.mock(ActorSystem.class);
  • 是的@Maciej,我只用这种方式编写了代码,但仍然出现错误。这是代码。
  • PowerMockito.mockStatic(ActorSystem.class); ActorSystem actorSystemMock = PowerMockito.mock(ActorSystem.class); Mockito.when(ActorSystem.create("payrollRun")).thenReturn(actorSystemMock); ActorRef actorSpy = Mockito.mock(ActorRef.class); Mockito.when(actorSystemMock.actorOf(new RoundRobinPool(anyInt()).props(Props.create(PayrollRunActor.class, null, null, null)))).thenReturn(actorSpy); Mockito.doNothing().when(actorSpy).tell(Mockito.any(PayrollRun.class), actorSpy);
猜你喜欢
  • 2020-04-15
  • 2015-07-16
  • 2011-10-09
  • 1970-01-01
  • 1970-01-01
  • 2020-04-26
  • 1970-01-01
  • 2015-11-06
  • 1970-01-01
相关资源
最近更新 更多