The other answer gives good hints, but is missing a crucial point: you could improve your design to make your production code easier to test.
Your problem is that you are mixing up responsibilities here: there is that "core" function that readLines() is supposed to do; and then, there is a requirement to provide a command line interface. You push all of that into a single method; and that makes it hard to test that method.
Instead; you could change your method to:
void processLines(List<String> keys, List<String> modules) {
...
Meaning: instead of asking the user inside of the method for his input, you provide that input directly to that method. Now you don't need to mock a Console, or anything else. You have a method that receives two lists; and when using dependency injection; you could easily verify that the communication/header objects see the calls that you would expect; dependent on the input your test gives to that method.
And then; when all of that works, you can write a little helper class like:
public static void main....
List<String> keys = new ArrayList<>();
... loop code asking user for his input ...
someLine.processLines(keys, modules);
Even that could be unit tested; but if you really keep it on such a simple level; you probably don't need that - as the idea is that you call it on the command directly.
Long story short: when you get the feeling that your production code is hard to test, then this is because of a "bad design" in the first place. When code is hard to test, it will also be hard to fix, enhance, or reuse. Your method only works in context of a user providing input. My version can directly be used for other scenarios as well. And as said: it would be much easier to test.