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: 
TDD isn't limited to unit tests, it can be applied at any granularity. What you're trying to do is covered by [acceptance test-driven development](https://en.wikipedia.org/wiki/Acceptance_test-driven_development) (ATDD) which adds an outer loop to the classic red-green-refactor cycle: you write a failing acceptance test first which should help you come up with a skeleton of your overall program, then you write failing unit tests before finally implementing the actual logic. The acceptance tests ensure that you are building the right thing and your various components are wired together correctly, while the unit tests ensure that your components are implemented correctly.

There is an excellent book on this topic called [Growing Object-Oriented Software, Guided by Tests](https://rads.stackoverflow.com/amzn/click/com/0321503627) that goes into detail about this process and includes a worked example of a GUI application built from scratch using TDD.
If you really want follow the "don't write code unless .." rule dogmatically, make your "main program" a class of its own, with injected dependencies for the 3 steps you scetched in your question, and mocks which are designed to allow verifying that the main processing functions were called:

```
    TestMain()
    {
         //arrange
         DatabaseReader dr = new DatabaseReaderMock();
         Simulator sim = new SimulatorMock();
         OutputWriter ow = new OutputWriterMock();

         //act
         MainProgram mainProgram = new MainProgram(dr,sim,ow);
         mainProgram.Run();

         //assert
         Assert(dr.ReadDataWasCalled());
         Assert(sim.SimulateWasCalled());
         Assert(ow.WriteOutputWasCalled());
     }

```

This unit test design expects the MainProgram class to look somehow like this:

```
class MainProgram
{
     // DatabaseReader, Simulator  and OutputWriter are just interfaces
     MainProgram(DatabaseReader dr, Simulator sim, OutputWriter ow)
     {
         _dr=dr;
         _sim=sim;
         _ow=ow;
     }
     Run()
     {
         var data = _dr.ReadData();
         var output = _sim.Simulate(data);
         _ow.WriteOutput(output);
     }
}

```

You could also extend the test above and verify that Simulate was called with the output of "ReadData", and "WriteOutput" was called with the output of simulate, or that the three functions are called in that particular order (however, that may be at the borderline of expecting a specific implementation).

If you think this is worth the hassle, then go ahead. As an alternative, you may consider to rely on integration tests for this part of your system and do not write such a unit test.

Personally, I prefer pragmatism over dogmatism and would probably do the latter, as long as the MainProgram stays to be that simple. Moreover, whenever possible, I would try to keep the dataflow simple by a clear separation between processing components (`DatabaseReader`, `Simulator`, `OutputWriter`) and components which just orchestrate them (`MainProgram`).

IMHO "TDD by the book" rarely pays off for purely orchestrating components, but YMMV.