> I'm implementig a simple command line game

I frequently use this as a starting point for TDD exercises. It's a really good choice, as it forces you to discover important distinctions between logic and effects.

> As you can see, the main logic it's inside the Run function, which makes sense to expose as public, so that the Main() function that creates a Game class also calls Run(), but since all the logic will be a bunch of private functions, how do I create it from the tests first?

Your program is going to have a natural break between two parts - I/O and logic. Testing I/O is harder - it lives higher up the [test pyramid][1] than the logic tests. This is in part because the IO system tends to be shared; you can't as easily run two tests concurrently without them interfering with each other.

So you are likely to end up with some tests that look like

 cat input | my-game > actualOutput
 diff actualOutput expectedOutput

If you read _Growing Object Oriented Software, Guided By Tests_, you find that Freeman and Price will talk about dedicating their initial work to a test like this run as part of their build/deploy pipeline. It won't be a fancy implementation of the game yet (think hello world), but it will be enough to demonstrate that the project delivery system works.

Moving down the pyramid, we're going to find some tests that use [test doubles][2]; in this case, a "stub" or a "fake" for STDIN and a "mock" or "spy" for STDOUT. So imagining an implementation of `Game.main`, it might look like:

 void main (String [] args) {
 Game.run(System.in, System.out);
 }

or

 void main (String [] args) {
 Game g = new Game(System.in, System.out);
 g.run();
 }

You don't normally try to "unit test" this `main` method, because it is directly coupled to the shared instances of STDIN and STDOUT. Instead, the unit tests will measure the behavior of `run` using test doubles. We'll be asserting on information collected by the implementation of STDOUT that we provide during the test.

This is an important idea in TDD - we've deliberately designed the interface of game such that it can be tested in a more cost effective way.

JBrains wrote:

> If we want to introduce indirection, then we ought to introduce the smallest indirection possible. And we absolutely must try to introduce better abstraction. 

What we've done here is introduce a _seam_, which is the indirection that gives us control of the subject in the test environment. What we want to be discovering as we iterate on the internal design is better abstractions.

Note that, to this point, we haven't really done anything to introduce `Player`, `Enemy`, or any of the other domain abstractions that we expect to use. Those concepts are things that we expect to discover and extract during the refactoring step. Once you have discovered them, and feel that their API is sufficiently stable, you can start writing tests that specifically measure those elements.

Which is to say, the tests of the Game, working seam to seam, tend to be too big, in this sense: they span a lot of distinct behaviors. Because there are so many behaviors within the scope of the test, those tests tend to be "brittle"; we decide one little bit of behavior should be slightly different, and the entire test falls over.

> The only thing that comes to my mind is or to use Mock, which I really don't want to

Well, then lets go a level deeper; STDIN and STDOUT are sources of _messages_ to and from the IO System. From a very high level, we have some thing like

 String [] lines = read(this.stdin)
 String [] output = this.gameLogic(lines)
 writeTo(this.stdout, output)

`gameLogic` here doesn't depend on the IO system at all; it only cares about the data structure passed to it. So you can test everything that is interesting and unique about your game in memory, without needing to worry about the IO system at all.

You probably wouldn't choose this API, because we like to think of games being interactive. Instead, you'd probably end up with something like a state machine

 while(game.running) {
 String line = nextLine(this.stdin)

 game.onLine(line)
 String output = game.output()

 writeTo(this.stdout, output)
 }

Again, that middle section is just passing in memory data structures into and out of the game logic that you actually care about. You "discover" this sort of API while iterating on the design that uses the mocks, but once this API is stable you can start writing tests directly against the API.

Gary Bernhardt's [Boundaries][3] talk is a great introduction to this concept.
 
From this point, it's turtles all the way down; you continue to add new tests for desired behavior, and iterate on your internal design, and as concepts like `Player` and `Enemy` begin to stabilize, you start writing even smaller tests directly against those elements.

 [1]: https://martinfowler.com/articles/practical-test-pyramid.html
 [2]: https://martinfowler.com/bliki/TestDouble.html
 [3]: https://www.destroyallsoftware.com/talks/boundaries