I’m like a test unitarian. Unit tests? Great. Integration tests? Awesome. End to end tests? If you’re into that kind of thing, go for it. Coverage of lines of code doesn’t matter. Coverage of critical business functions does. I think TDD can be a cult, but writing software that way for a little bit is a good training exercise.

I’m a senior engineer at a small startup. We need to move fast, ship new stuff fast, and get things moving. We’ve got CICD running mocked unit tests, integration tests, and end to end tests, with patterns and tooling for each.

I have support from the CTO in getting more testing in, and I’m able to use testing to cover bugs and regressions, and there’s solid testing on a few critical user path features. However, I get resistance from the team on getting enough testing to prevent regressions going forward.

The resistance is usually along lines like:

  • You shouldn’t have to refactor to test something
  • We shouldn’t use mocks, only integration testing works.
    • Repeat for test types N and M
  • We can’t test yet, we’re going to make changes soon.

How can I convince the team that the tools available to them will help, and will improve their productivity and cut down time having to firefight?

  • eksb@programming.dev
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 year ago

    Two rules:

    1. All code gets reviewed by a team member before getting merged.
    2. Fail code reviews if there are not sufficient tests.
    • Skyzyx@lemmy.world
      link
      fedilink
      English
      arrow-up
      1
      ·
      edit-2
      1 year ago

      I think that instead of “forcing tests”, you should instead focus on “proving quality.” You think that works the way you thought? Cool. How do you know? What if they were to use 128 NUL bytes? Would it still do the right thing? Cool. How do you know?

      Ensuring quality is a larger concept than simply writing tests, but writing tests is definitely part of it. I think if you aim higher and teach the provability of quality, then the better engineers will self-select by starting to write tests.

      “If you want to build a ship, don’t drum up people to collect wood and don’t assign them tasks and work, but rather teach them to long for the endless immensity of the sea.” — Antoine de Saint-Exupery

      Additionally, if you’re one person against the world, you’re going to have a tough time. Build alliances. Partner with people who will reinforce the message. If you are the only one telling them something they don’t like, they will shun you for it. But if you partner with allies who all have the same message, people are more likely to start to listen. It starts to become a community.

      And if all else fails, prove the value of tests by going first. You can’t force anyone to do anything. But you can start doing this yourself. At some point, if code gets called into question, you can look at the tests together to see what’s covered and how that thing is supposed to work. It’s all part of letting the robots do what the robots are good at, which frees you up to do the things that you’re good at.

    • sip@programming.dev
      link
      fedilink
      arrow-up
      0
      ·
      1 year ago

      yea but if we both aren’t really keen on writing tests and I review you, it would be in my lazy ass’ interest to 👍 without tests.

      • CodeMonkey@programming.dev
        link
        fedilink
        arrow-up
        1
        arrow-down
        2
        ·
        1 year ago

        That should be a disciplinary issue. The engineers in question should be brought forth in front of management to explain why they thought that this particular change should be exempt from testing and why this was not explained, in detail, in the code review.

        • lysdexic@programming.dev
          link
          fedilink
          English
          arrow-up
          5
          ·
          1 year ago

          That should be a disciplinary issue.

          And that’s how you get teams to stop collaborating and turn your work environment to shit.

  • lysdexic@programming.dev
    link
    fedilink
    English
    arrow-up
    1
    ·
    edit-2
    1 year ago

    Here’s a way to convince a team to write unit tests:

    • setup a CICD pipeline,
    • add a unit test stage,
    • add code coverage calculation,
    • add a rule where unit tests fail if a code coverage metric drops.
    • if your project is modularized, add pipeline stages to build and test and track code coverage per module.

    Now, don’t set the threshold to, say, 95 %. Keep it somewhat low. Also, be consistent but not a fundamentalist.

    Also, make test coverage a part of your daily communication. Create refactoring tickets whose definition of done specifies code coverage gains. Always give a status report on the project’s code coverage, and publicly praise those who did work to increase code coverage.

    • Reader9@programming.dev
      link
      fedilink
      English
      arrow-up
      2
      ·
      1 year ago

      Focusing on code coverage (which doesn’t distinguish between more and less important parts of the code) seems like the opposite of your very good (IMO) recommendation in another comment to focus on specific high-value use-cases.

      From my experience it’s far easier to sell the need for specific tests if they are framed as “we need assurances that this component does not fail under conceivable usecases” and specially as “we were screwed by this bug and we need to be absolutely sure we don’t experience it ever again.”

      Code coverage is an OK metric and I agree with tracking it, but I wouldn’t recommend making it a target. It might force developers to write tests, but it probably won’t convince them. And as a developer I hate feeling “forced” and prefer if at all possible to use consensus to decide on team practices.

      • lysdexic@programming.dev
        link
        fedilink
        English
        arrow-up
        1
        ·
        1 year ago

        Focusing on code coverage (which doesn’t distinguish between more and less important parts of the code) seems like the opposite of your very good (IMO) recommendation in another comment to focus on specific high-value use-cases.

        The usefulness of code coverage ratios is to drive the conversation on the need to track invariants and avoid regressions. I agree it’s very easy to interpret a metric as a target to optimize, but in this context coverage ratios is primarily used to raise the question on why wasn’t a unit test added.

        It’s counterproductive to aim for ~100% but without this indicator any question or concern regarding missing tests will feel arbitrary. With coverage ratios being tracked, this topic becomes systematic and helps build up a team culture that is test-driven or at least test-aware.

        Code coverage is an OK metric and I agree with tracking it, but I wouldn’t recommend making it a target. It might force developers to write tests, but it probably won’t convince them.

        True. Coverage ratios are an indicator, and they should never be an optimizable target. Hence the need to keep minimum coverage ratios low, so that the team has flexibility to manage them. Also important, have CICD pipelines export the full coverage report to track which parts of the code are not covered.

        The goal is to have meaningful tests and mitigate risks, and have a system in place to develop a test-minded culture and help the team be mindful of the need to track specific invariants. Tests need to mean something and deliver value, and maximizing ratios is not it.

  • CasualTee@beehaw.org
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 year ago

    I tried to introduce tests to one of the team I worked at. I was somewhat successful in the end but it took some time and effort.

    Basically, I made sure to work with the people interested in testing their code first. It’s good to have other people selling testing instead of being the only voice claiming testing will solve all some problems.

    Then I made examples: I tried to show that testing some code, believed to be untestable, was actually not that hard.

    I was also very clear that testing everything was not the end goal, but, new projects especially, should try and leverage testing. Both as a way to allow for regression testing later on and to improve the design. After all, a test often is the first user of a feature. (This was for internal libraries, I expect it would be a harder sell for GUI where the end design might come from a non programmer such as a UX designer).

    At this point, It was seen as a good measure to add a regression tests for most bugs found and fixed.

    Also, starting from the high level, while harder (it’s difficult to introduce reliable integration and end to end tests), usually yields benefits that are more obvious to most. People are much less nervous reworking a piece of code that has a testing harness, even if they are not in a habit of testing their code.

    I did point at bugs that could have been easily prevented by a little bit of testing, without blaming anyone. Once the framework is in place and testing has already caught a couple of mistakes, it’s much harder to defend the argument that time spent testing could be better spent elsewhere. And that’s where we started to get discussions on the balance to strike between feature work and testing. It felt like a win.

    It took two years to get to a point where most people would agree that testing has its uses and most new projects were making use of UT.

  • leds@feddit.dk
    link
    fedilink
    arrow-up
    1
    ·
    1 year ago

    Got a bug? Write a test to proof you can reproduce it , proof you fixed it and make sure it doesn’t come back.

  • Skyzyx@lemmy.world
    link
    fedilink
    English
    arrow-up
    1
    ·
    1 year ago

    Sounds like a bunch of junior engineers with senior job titles.

    “Senior” is the new mid-level.

  • mspencer712@programming.dev
    link
    fedilink
    English
    arrow-up
    0
    ·
    1 year ago

    Support from the CTO means he’s willing to pay for it. Test coverage is a paid-for feature that your team is committing to work on. Would they refuse client-funded work because the client might have to pay for rework later?

    Maybe presenting it that way could get people past their hang-ups. Good luck.

    • sip@programming.dev
      link
      fedilink
      arrow-up
      0
      ·
      edit-2
      1 year ago

      yea but the counter was that they need to move fast.

      In the beginning, tests slow you down, but in time, the amount of bugs tests catch and the confidence in refactoring adds up to way more saved time.

      • Skyzyx@lemmy.world
        link
        fedilink
        English
        arrow-up
        1
        ·
        1 year ago

        Right. “Move fast” means that it’s going to get progressively worse, and 2 years from now it will all collapse under the weight of its bugs.

        Think of tech debt as cancer, and tests as chemotherapy. It might suck for a while, but it can also make you much better.

  • Reader9@programming.dev
    link
    fedilink
    English
    arrow-up
    0
    ·
    edit-2
    1 year ago

    We can’t test yet, we’re going to make changes soon

    This could be a good opportunity to introduce the concept of test-driven development (TDD) without the necessity to “write tests first”. But I think it can help illustrate why having tests is better when you are expecting to make changes because of the safety they provide.

    “When we make those changes, wouldn’t it be great to have more confidence that the business logic didn’t break when adding a new technical capability?”

    You shouldn’t have to refactor to test something

    This seems like a reasonable statement and I sort of agree, in the sense that for existing production code, making a code change which only adds new tests yet also requires refactoring of existing functionality might feel a bit risky. As other commenters mentioned, starting with writing tests for new features or fixes might help prevent folks feeling like they are refactoring to test. Instead they’re refactoring and developing for the feature and the tests feel like they contribute to that feature as well.

    • Skyzyx@lemmy.world
      link
      fedilink
      English
      arrow-up
      1
      ·
      1 year ago

      I think it depends. If you have to refactor in order to test, you probably built it poorly the first time around.