Не изменяя класс другого человека, как я могу потребовать, чтобы он использовал мою версию Scanner (скрытой как внутренний класс) вместо java.util.Scanner? - PullRequest
0 голосов
/ 04 ноября 2019

Для развлечения (и для использования в моем классе в качестве учебного пособия) я пишу программу, похожую на JUnitTests. Я хочу использовать его для запуска тестов кода, написанного старшеклассниками. Когда студент пишет код, который получает пользовательский ввод через System.in с помощью сканера, я хочу «взломать» сканер, чтобы предоставить мои собственные заранее определенные пользовательские входы. У меня все отлично работает, за исключением того, что я хочу, чтобы мой Сканер был внутренним классом Автотестера.

Пример, приведенный ниже, сильно упрощен, но все понятно.

Допустим, студенты пишут этот код:

import java.util.*;
public class Practice {  
    public static void practiceScanners()  {
        Scanner console = new Scanner(System.in);                 
        System.out.print("Type first name, age, and address >> ");
        String name = console.next();
        int age = console.nextInt();
        String address = console.nextLine();
        System.out.println(name + " is " + age + " and lives at" + address + ".");
    }
}

Затем, скажем, у меня есть класс с именем AutoTester, который выглядит примерно так: псевдокод:

public class AutoTester {

    public main() {
        * use JavaCompiler from ToolProvider to compile Practice.java
        * use reflection to invoke Practice.practiceScanners()
             * (hopefully) have student code use my Scanner instead of java.util.Scanner
             * collect output of running the student code 
             * compare against expected output
    }

    //My version of Scanner is an inner class within AutoTester
    public class Scanner { 
        private String script = "Bob 13 42 Maple Drive";
        <* implementation not shown *>    
    }

}

ЕслиЯ перемещаю свою версию Scanner в собственный файл Scanner.java, это работает просто отлично. Код студента использует мой (локальный) сканер, прежде чем искать в java.util. Но когда я перемещаю свой сканер в автотестер как внутренний класс, код студента не знает, где его искать. И я не хочу каким-либо образом редактировать код ученика (например, изменить строку создания экземпляра сканера, чтобы сказать, что новый AutoTester.Scanner (System.in))

Есть ли способ дать мой AutoTester.ScannerПриоритет перед java.util.Scanner при компиляции / запуске программы студента без внесения каких-либо изменений в их код?

1 Ответ

1 голос
/ 04 ноября 2019

Так не работает, к сожалению. Имя класса пользовательского сканера на самом деле AutoTester.Scanner, вы определили его в тестовом классе и, кроме похожего имени, оно не имеет ничего общего с java.util.Scanner. Так что это никак не повлияет на Practice.

Вам придется реструктурировать код Practice, чтобы использовать @Inject s (например, с CDI ) для чего-то, чтоработает как сканер. Затем используйте mockito ( @ Mock, @ InjectMocks ) для подключения сканера. Это много тяжелой техники, хотя. В качестве альтернативы вы могли бы спроектировать Practice так, чтобы он принимал Scanner как параметр конструктора или как свойство.

Но, тем не менее, у вас все еще есть проблема, что Scanner является конечным классом, который не может быть расширен. Таким образом, для этой цели вам нужно будет ввести свой собственный интерфейс, в одном случае положить под крышку java.util.Scanner, а в другом - альтернативный сканер.

...