Не могу издеваться над методом java.lang.System # exit (int) с PowerMock - PullRequest
0 голосов
/ 05 января 2019

У моего приложения есть поток, в конце которого вызывается метод System.exit(int).

Я пытаюсь проверить этот поток, запустив тест с использованием TestNG.

Однако, когда я запускаю тест, я получаю странное сообщение, хотя тест завершен:

enter image description here

Просто для того, чтобы найти основную причину, я удалил System.exit(int) из реального потока и тест прошел, как и ожидалось, поэтому проблема здесь заключается в методе System.exit(int).

Чтобы решить эту проблему, я попытался высмеять проблемный метод, но не смог найти правильный способ сделать это. Вот что я сделал

  1. Я добавил java.lang.System.class в @PrepareForTest в классе испытаний.
  2. добавлено PowerMockito.mockStatic(java.lang.System.class) в тесте
  3. Я пытался смоделировать метод двумя способами:

    а.

        PowerMockito.replace(PowerMockito.method(System.class, "exit", int.class))
        .with((proxy, method, args) -> null);
    

    При выполнении этого способа похоже, что макет не работает, потому что в конце теста я получаю то же сообщение, которое я также получал, когда не применял никаких макетов в System.exit (int)

enter image description here

б.

PowerMockito.doNothing().when(System.class, "exit", Mockito.any());

Таким образом, я получаю это исключение в начале теста:

org.powermock.reflect.exceptions.MethodNotFoundException: No method found with name 'exit' with parameter types: [ <none> ] in class java.lang.System.

Я уже издевался над некоторыми методами таким образом, не уверен, почему с System.exit(int) он не работает.

Есть идеи? Спасибо

1 Ответ

0 голосов
/ 11 марта 2019

Интересный вопрос, я тоже не знал, но, видимо, это возможно без использования Powermock, с помощью SecurityManager. Цитата из оригинального сообщения :

Сегодня я писал тест для одного из наших инструментов командной строки, и у меня было эта проблема, когда метод сбрасывает все, что я действительно нужно было позвонить, так как это результат, который я проверял, также называется System.exit (). Я должен был найти способ проверить это в любом случае. я думал об использовании PowerMock и системы издевательств, но это было бы было сложно, потому что я должен был бы найти точный класс вызова System.exit (). Так что вот еще одно решение, чтобы избежать System.exit для выхода (да, возможно, я не знал об этом либо).

Секреты заложены в механизме SecurityManager Java этого класса. не только позволяет проверить разрешения, но и проверить выход событие. Поэтому вы можете выбросить исключение, если хотите остановить выход

Ниже приведен полный образец, который я тестировал в IJ. Пожалуйста, обратите внимание, что образец, как предполагается, терпит неудачу специально:

java.lang.AssertionError: 
Expected: is <10>
     but: was <5>
Expected :is <10>
Actual   :<5>

package com.example;

import org.junit.Test;

import java.security.Permission;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

public class SystemExitTest {

    @Test
    public void shouldExitWithSpecificCode() {
        //save the initial security manager (probably null)
        SecurityManager initialSecurityManger = System.getSecurityManager();
        try {
            // set security manager
            System.setSecurityManager(new NoExitSecurityManager());

            // execute code under test
            new MyClass().exit(5);

            // ensure this point is not reached by any chance
            fail("Should've thrown ExitException");
        } catch (ExitException e) {
            // validate exit code
            assertThat(e.status, is(10)); // <== this fails on purpose
        } finally {
            // restore initial security manager (otherwise a new ExitException will be thrown when the JVM will actually exit)
            System.setSecurityManager(initialSecurityManger);
        }
    }


    // class under test
    public static class MyClass {
        public void exit(int code) {
            System.exit(code);
        }
    }

    // exception to be thrown by security manager when System.exit is called
    public static class ExitException extends SecurityException {
        public final int status;

        public ExitException(int status) {
            this.status = status;
        }
    }


    // custom security manager
    public static class NoExitSecurityManager extends SecurityManager {
        @Override
        public void checkPermission(Permission perm) {
        }

        @Override
        public void checkPermission(Permission perm, Object context) {
        }

        @Override
        public void checkExit(int status) {
            super.checkExit(status);
            throw new ExitException(status);
        }
    }
}
...