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: 
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.
I think the point is being missed here.

You have two questions in fact:

* One is how to test a function/class.
* The other is what a test means in TDD

---

Testing a function/class should already be quite well practiced by you based on the question.

The answer is dependency injection.

The problem is that your main function assumes to know more than it should. It does not know every situation in which it might be created, same as any other class/function.

The solution is to humble it. It should accept those dependencies somehow, be it through a constructor, a property (which has some default), or an optional parameter.

This will make the program even more capable, as it is now much more configurable and testable.

If for some reason the test is complex to setup, then the function/class needs to be broken down. After all you are essentially asking anyone who uses your function/class to know all of this information in order to use it well. Most of the time that user is yourself.

---

As for the second question (which you didn't state but is lurking back there)...

English is tricky in that the meaning of a word can be broad or even change in a different context or usage. 'Test' is one such word.

The problem is that there are several kinds of test:

* Aspirational Tests: These test describe something to be desired. In short a kind of Specification.
* Adversarial Tests: These tests probe for weaknesses and exploitable gaps. In short evidence of safety/security.
* Affirmational Tests: These tests pin down something that exists. In short evidence of organic code.

In TDD the goal is to write Aspirational tests.

The best time to write an aspirational test is when the code doesn't exist, or in a pinch without looking at the code (and you've had it unload from your own memory).

The worst time to write such tests is when the code exists. The temptation is very high to instead write an Affirmational, or an Adversarial test. Those tests have their benefits, but they won't deliver the thinking that an Aspirational test does.

An Aspirational test challenges you to simplify your tests. The simpler the tests:

* the fewer prerequistes/knowledge needed to use the code effectively,
* the more likely the code can be reused,
* the easier it is to change the aspired for behaviour.
* the easier it is to burn the implementation down and rebuild it,
* the easier it is for another programmer (or your future self) to understand and maintain the code

Similarly this principal can be applied at higher levels of modularity under different names. eg: BDD, ATDD.