При использовании метода void метод 'локальное имя класса несовместимо с именем класса потока "void" "при де / сериализации через Spark - PullRequest
1 голос
/ 13 июня 2019

При попытке создать тест для приложения, использующего Spark, я сталкиваюсь со следующей ошибкой:

java.io.InvalidClassException: java.lang.Void; local class name incompatible with stream class name "void"
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:620)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1843)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1713)
    at java.io.ObjectInputStream.readClass(ObjectInputStream.java:1678)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1518)
    at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2245)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2169)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2027)

Это происходит только в том случае, если я высмеиваю некоторые классы, которые имеют void методы, которые будут вызываться в какой-то моментво время запуска тестируемого устройства.

Например, мой код:

public class MyTest {

    private MyClass uut;

    private Writer writer;

    @Captor
    private ArgumentCaptor<Dataset<Row>> rowCaptor;

    @Before
    public void setUp() {
        initMocks(this);

        writer = mock(Writer.class);
        uut = new MyClass(writer);
    }

    @Test
    public void testSomething() {
        // given

        // when
        uut.process();

        // then
        verify(writer, times(2)).write(rowCaptor.capture());
        List<Dataset<Row>> result = rowCaptor.getAllValues();
        // ...
    }
}

1 Ответ

2 голосов
/ 13 июня 2019

Кажется, проблема в том, что Mockito сериализует свои внутренние прокси-классы.Это отрицательно сказывается только в том случае, если задачи / задания, которые вы запускаете в Spark, действительно сериализуются и десериализуются.

В org.apache.spark.scheduler.ShuffleMapTask#runTask задача десериализуется.Spark в основном делает в этот момент:

new JavaDeserializationStream(new ByteBufferInputStream(ByteBuffer.wrap(this.taskBinary.value())), ClassLoader.getSystemClassLoader()).objIn.readObject()

, который выдает точное сообщение об ошибке против

new ObjectInputStream(new ByteArrayInputStream(this.taskBinary.value())).readObject()

, которое будет работать и правильно анализировать объект.

В частности, кажется, что существует несоответствие между тем, как Java / Spark ожидает сериализации void методов, и тем, что фактически делает Mockito: "java.lang.Void" / "Void" против "void".

К счастью, Mockito позволяет вам указать способ сериализации своих макетов:

MockSettings mockSettings = Mockito.withSettings().serializable(SerializableMode.ACROSS_CLASSLOADERS);
writer = mock(Writer.class, mockSettings);

После этого изменения тест должен работать.


Обратите внимание, что, например, verify вызовыtricky / не будет работать должным образом, если макет был сериализован, отправлен куда-то, десериализован и затем использован снова.Вызовы на макете не будут видны оригиналу writer.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...