Let's try an answer then. From what I understand we actually have two questions here:
How can you apply TDD when adding new features to a codebase that has not been developed with TDD itself?
How can you add tests for tightly coupled code?
Answer to question 1:
First of all, test-driven development is used for new code. By the very name of it TDD cannot be used to add tests to already existing code, because obviously, the development would not be driven by tests in that way. So TDD is out for question 2.
For question 1, however, you run into problems as soon, as your code interacts with the existing codebase in some way. Any completely new modules/classes can easily be developed with a TDD approach of course. When you have an interface to the existing code, you can still develop with a TDD approach, but that requires you to provide a mock or stub for the interface. This does not necessarily mean that you re-implement behavior.
A mock/stub need not have the full behavior of your original object. For example, it is perfectly fine to have a database stub that returns a constant list of thingies for every query you give it. It is sufficient to test whatever behavior you want to test that needs to work with that return list. You are after all not testing the database layer itself at that moment.
The problem gets more difficult, when you have to add code to existing classes/modules within a method, or maybe add calls to a new method. In those cases you suffer from the lack of tests of the original codebase and it can become troublesome to write tests. Mostly, this should be dealt with by improving the original codebase - see answer to question 2.
Answer to question 2:
When you have an existing codebase with high coupling and you want to test it, then first of all you should have a good reason to do so. It's a nice exercise, but does not per se add any value to your product, so you need some reason, where the existence of these tests gives you a future benefit.
Here's a bunch of typical reasons, why you want to do this:
The codebase is legacy and you are assigned to its maintenance. The tests will give you a better understand of what the code does, and provides a safety net against introducing errors when you make changes in the future.
The codebase will be significantly changed to adapt the product for new features. In that case you will be working with the code for a while, which means you will reap the benefits of the created tests during your ongoing development.
The codebase is subject to be replaced. For example, your database layer may be exchanged for another one. In that case, the tests will be used as a safety net to detect if the new database layer behaves differently.
Once you know why you want to write the tests, you can also focus your tests more thoroughly. If you want to continue development on the source, you will need fine-grained unit tests. If instead you just want to have tests against the whole module, any kind of integration test will suffice.
From what I can guess about your intentions, I'd say that your most likely reason seems to be that you have a legacy codebase that you want to continue working upon. In that case, the tests are step one and provide you a foundation upon which you can perform refactoring operations. Given the tests, you can rather quickly work on the coupling problems and improve the code design to make it more robust for future development.
Finally, to address your example about sorting lists: You need to think about which module is responsible for the sort operation, and whether or not it makes sense for you to test it. If you delegate sorting to the database layer (via sqlite queries), then you only need to test it if you plan to use the test against a new database layer implementation, in which you suspect sorting to behave differently. However, you need not re-implement any sorting to test your UI-side, because the UI itself has no sorting behavior whatsoever that could be tested. All you can test is that the UI respects the order of the elements it is given. In other words, there is no coupling between the database and the UI with respect to sorting. The database is responsible for sorting and just gives an ordered list to the UI. And the UI is only responsible for representing an ordered list of elements - no matter which order that is. Of course, you can also test your controller such that it does in fact call the correct query to create the requested sorting order.
It all comes down to the point that you want loose coupling: it forces you to define proper interfaces between your components, it allows you to test each individual component thoroughly and without needing any of the other component implementations.