How do you implement TDD in reality?

Say you have a system that is TDD ready, not too sure what that means exactly but you can go write and run any unit tests.

And for example, you need to generate a report that uses 2 database tables so:

1. Read/Query
2. Processor logic
3. Output to file

So 1 and 3 are fairly straightforward, they don't change much, just mock the inputs.

But what about #2. There's going to be a lot of functions doing calculations, grouping/merging the data. And from my experience the code gets refactored a lot. Changing requirements, optimization (first round is somewhat just make it work) so entire functions and classes maybe deleted. Even the input data may change. So with TDD wouldn't you end up writing a lot of throwaway code?

A lot of times I don't know exactly what I want or need other than I need a class that can do something like this... but then I might end up throwing the whole thing out and writing a new one one I get a clearer idea of what i or the user wants or needs.

Last week I was building a new REST API, the parameters and usage changed like 3 times. And even now the code is in feasibility/POC testing just to figure out what needs to be used. Do I need more, less parameters, what should they be. I've moved and rewritten a lot of code because "oh this way won't work, need to try this way instead"

All I start with is my boss telling me I need an API that lets users to ... (Very general requirements).

  • 1
    Just write tests for everything that can be tested, as much as possible.
    Code changes, tests change with it. If the code gets thrown away, so do the tests.
  • 0
    @ravijojila but what about at the start where the plan is basically like a blob, a gist. There's like a 50% chance most of the code will change a lot because the original requirements or feasibility using the current approach changes.

    Like you don't really understand the details of the problem, need to just try it and see what's needed.

    You look at a class/the app so far and just go this whole approach doesn't work, has to be redone.
  • 1
    If it's pushed to the master branch it's pushed with tests. If there's 50% chance most of the code will change, there's same chnce that tests will change.
    You don't need to write tests while in poc fase.
  • 1
    @ravijojila well I'm starting with a blank slate so I have a working POC but then when I extend the use case, I run into a design problem. Need to change, restructure a lot of the app to have it built more correctly.

    Guess it's like having a target but while getting to it realizing that's not quite the right target. Or I guess realizing some assumptions are just wrong/invalid. Like for example, that a value like Date used for as an Unique ID is actually not unique for certain cases. But from a user point of view, they should not know/care. So basically have to rethink/redesign the a big chunk to make it work for everything. And that pretty much means throwing out all existing tests because in this new structure, it just doesn't work.

    Some of these things you can't plan beforehand or just don't have the info at the time. And only realize when it's in front of you and pretty just go "oh shit... looks like i need to redo this..."
  • 0
    The other issue is also I work with a few languages so all the unit testing frameworks are different: Java, JS (backend, GUI), C# so hoq do you deal with the context switching. Even how the tests are run and built are very different.
  • 0
    @SHA-16384 boss says we need a new server app that does .... Go figure out what you need and build it.

    I'm usually the guy building the new projects, apps. So the issue is how to apply TDD when you don't really know what you'll need or how the project will end up shape/structure wise?
  • 0
    Wait Mocha/Chai you can run a specific tests/functions?

    From what I understand from our code. We have a Grunt command that runs tests. It starts a Dev server/API, loads the mock data into the Dev DB, and then runs all the tests. And actually all the tests are calling URL paths, not particular JS functions.
  • 1
    Well, for nr 2 you'd probably have some public methods to create? If so, you can test those. I assume that these methods representing your public interface won't change that much. If you expect it to change a lot, reconsider your design! On a high leve of abstraction you could say: I have some input, which needs to be processed to some output. Encapsulate what varies: the input and output could be separate.types,.so you don't have to change your public interface.. if you need lots of different calculations, transformations etc: abstract them out! Think and apply SOLID. Then delegate your process method to all these types that do the transformation, calculation etc and unit test those. Then your process method will stay clean and easy to test without a lot of rework needed for every change. Also make good use of factory methods,.reusable mocks etc as than can save lots of work revising tests.
  • 0
    @CodeMasterAlex so you mean instead of using primitives, pass like a ReportParams instead?

    And just treat the public methods?

    For TDD though don't you need to test all functions? Last time in Java, I was using WhiteBox to access different private methods because needed code coverage. Or because the public methods have a lot of overhead or branching. Like for 1 class the only Public method is generateReport but then testing that would be basically be the same as just running the program itself.
  • 1
    @billgates If testing that would basically be the same as runing the whole program, things need to be separated more. If you require testing private methods, take those methods out into separate classes that each do just 1 thing and they do that 1 thing very good. Then you can test these classes. For generating the report you could, for example, create tests on that 1 public method to verify if each of the other classes (or a mock.of them) have their methods invokes as you'd expect them to be when you pass a certain configuration of report parameters. Also, you can test (using the real classes, not mocks) if a certain output is indeed as expected based on certain report parameters. In general with TDD we create tests for the public methods: they are in fact what the consumer of those methods use, so we try to guarantee using tests that they behave as expected. The inner workings are less relevant.
Add Comment