This TestDispatcher instance does not itself execute any of the tasks. Instead, it always sends them to its scheduler, which can then be accessed via TestCoroutineScheduler.runCurrent, TestCoroutineScheduler.advanceUntilIdle, or TestCoroutineScheduler.advanceTimeBy, which will then execute these tasks in a blocking manner.
In practice, this means that launch or async blocks will not be entered immediately (unless they are parameterized with CoroutineStart.UNDISPATCHED), and one should either call TestCoroutineScheduler.runCurrent to run these pending tasks, which will block until there are no more tasks scheduled at this point in time, or, when inside runTest, call yield to yield the (only) thread used by runTest to the newly-launched coroutines.
If no scheduler is passed as an argument, Dispatchers.Main is checked, and if it was mocked with a TestDispatcher via Dispatchers.setMain, the TestDispatcher.scheduler of the mock dispatcher is used; if Dispatchers.Main is not mocked with a TestDispatcher, a new TestCoroutineScheduler is created.
One can additionally pass a name in order to more easily distinguish this dispatcher during debugging.