Question: Another name for this question could be: How to TDD the main function?

My situation: I'm writing a program from scratch that runs a sort of simulation, and I want to apply TDD to the whole development process. It seems straightforward to me when I think about the small detailed features, but at some point the program needs to *start*. For example, this is a rough outline of how the program will run:

1. Read data from a database.
2. Loop a bunch of times simulating the desired behavior.
3. Write the output somewhere.

I'm tempted to write a test like `testLoopProducesValidOutput` but that's basically just checking to see if the entire program ran correctly, which doesn't seem very unit-like for a unit test.

In the spirit of "don't write code unless you have a failing test", I don't quite understand what kind of test to write to actually get that initial high-level code written that isn't running the entire thing. How would one generally approach this kind of situation?

(Of course one solution is just to not strictly follow TDD for this part, but if there's another solution I'm open to learning before I give up. :) )

Answer: 
> 
> How to TDD the main function?
> 
> 
> one solution is just to not strictly follow TDD for this part
> 
> 
> 

For what it is worth, on my own authority this is precisely what I've given myself permission to do.

---

> 
> I conclude that there are two ways of constructing a software design: One way is to make it so simple that there are *obviously* no deficiencies -- [C.A.R Hoare, 1980](https://www.cs.fsu.edu/%7Eengelen/courses/COP4610/hoare.pdf)
> 
> 
> 

If we've written code that "obviously" has no deficiencies, are we really getting a good return on our investment trying to create tests to run in our refactoring loops?

Consider this sketch of a main method for a command line dice game:

```
// Java
public static void main (String [] args) {
    somethingMoreComplicatedButTestable(
        System.in,
        System.out,
        new Random()
    );
}

```

Do you really think an automated mistake detector targeting this code is going to pay for itself?

> 
> I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence -- [Kent Beck, 2008](https://stackoverflow.com/questions/153234/how-deep-are-your-unit-tests/153565#153565)
> 
> 
> 

Here, the confidence comes from being disciplined about two rules

* code that is hard to test must be too simple to break
* code that is complicated must be easy to test in isolation

---

> 
> TDD is an awareness of the gap between decision and feedback during programming, and techniques to control that gap. -- *Test Driven Development by Example*
> 
> 
> 

Simplicity is a valid technique for controlling that gap.

---

See also: [Mark Seemann's answer from 2014](https://stackoverflow.com/a/22979208/54734)
I am not a big fan of mocking. It is useful in certain very special scenarios, but if you need a mocking *framework*, in my opinion you are doing something wrong.

Certain things need to be mocked because they cannot (should not...) be done in a unit test. For example accessing the file system to write output files. Or logging into the real production system, or even the real development system.

But your own logic should never be mocked away. Because in the end, you have thousands of unit tests, *and not one of them* actually tests whether your program is working! Every one is testing a tiny bit of functionality packed into a huge mass of mocking. So thousands of test could be green but when actually put together without mocks, it still fails. At least the possibility exists, and the whole point of tests is to make sure there is no such possibility.

Things you need to modify (I'm not saying "mock", because you can just switch out implementations, no need for a mocking framework):

* Logging needs to log into a container that is accessible and constrained to that one test.
* Data input needs to come from a source in that test. For example an in-memopry database unique to that test with data you decide on for each test.
* Data output needs to go into a container that is accessible and constrained to that one test.

So your test should be your actual program, reading from an in-memory database, writing to an in-memory filesystem.

For the first test, it's an empty database. I don't know what that yields, maybe a file with no rows and just the column headers. Assert that. Done. Your first test is written and fails. Make it compile, build and light up green. Then add more.

The point is, do not waste 90% of your testing on building fancy mocks. Test *real* things. Test things that *need* testing, the mocking framework doesn't.

Next test might be with exactly one value in the database. That might yield a file of one row. And then your go to more complicated input and edge cases.

If you cannot build a *public input* for your test case, your program does not need that test case, or that functionality.

As an added bonus, if you test your programs *public interface*, you can refactor your heart out and you do not need to refactor your tests. Because they do what they were designed to do: test whether your program still *works*, not whether you have used those exact functions in that exact order.

To summarize:

* Test *reality*. Not your mocking framework.
* Test whether your program works, not what it does internally.
* Start with the simplest case: no data.
* Then branch out into all the test cases.