• philm@programming.dev
    link
    fedilink
    arrow-up
    1
    ·
    edit-2
    11 months ago

    And then there’s me, who almost never writes unit tests 😬

    (With strong typing I can minimize explicit tests, and I like to iterate fast, but I guess it really depends on what you’re developing, backend in production that is not allowed to fail, is probably something different than a game)

    • sugar_in_your_tea@sh.itjust.works
      link
      fedilink
      arrow-up
      3
      ·
      11 months ago

      Unit tests shouldn’t be testing types, even if your language isn’t typed. It should be testing logic and behavior. If there’s an if condition, it should be tested.

      • philm@programming.dev
        link
        fedilink
        arrow-up
        1
        ·
        11 months ago

        Yeah you’re right, tests should test logic. But static typing certainly helps reducing a lot of tests, which would be necessary in different untyped languages. Also you can sometimes encode your logic in types. Typing also helps reducing logic issues. But as previously said, it depends on what you’re doing. I’m prototyping/researching a lot, and tests often hinder progress for me. Maintaining a backend in production is a different story.

        • sugar_in_your_tea@sh.itjust.works
          link
          fedilink
          arrow-up
          1
          ·
          11 months ago

          That is absolutely true as well. We’re porting a codebase to TypeScript and we were able to eliminate a bunch of test cases that were essentially testing type-correctness (e.g. can’t pass a boolean to a date processing library). But those were bad tests to begin with, because there was no good reason for those tests to exist to begin with (we were pretty exhaustive with the invalid type checking even when the intended types were obvious).

          Strict typing helps eliminate useless tests. And Rust types go further than most languages, such as exhaustive match, types that can exclude zero, and the near-complete lack of a null value.

          If you’re never going to publish the code, I agree, tests aren’t necessarily helpful. Then again, I find writing tests helps me understand my own code better, so I still do it when doing research tasks (e.g. we were testing the potential performance benefits of porting an expensive algorithm to Rust, so my tests helped me benchmark it), though my tests are a lot less exhaustive and tend to be more happy path integration tests instead of proper unit tests.

          • philm@programming.dev
            link
            fedilink
            arrow-up
            1
            ·
            11 months ago

            I find writing tests helps me understand my own code better, so I still do it when doing research tasks

            Hmm interesting, I try to optimize readability of the actual code itself, so that when I read it again after some time, that I quickly get what this is about, if there’s a edge-case or something I thought about while coding, I’ll just add a TODO comment or something like that. I feel like reading tests is a “waste of time” for me most of the time (hard take I know ^^).

            But all this obviously only applies for researching and fluid code (code that likely will be refactored/rewritten soon), when it’s solid code targeting production etc. I’ll add unit tests if friction/hassle is low, and integration/E2E tests for the overall thing. But as I said, I’m mostly in fluid/fast moving codebases that are more difficult to test (e.g. because it does gpu rendering or something like that).

            • sugar_in_your_tea@sh.itjust.works
              link
              fedilink
              arrow-up
              1
              ·
              11 months ago

              When I jump into a new codebase, my first instinct is to look over the examples and the unit tests to get a feel for how things are intended to work.

              When prototyping, I generally write a few “unit” tests as a form of example code to show basic usage. For example, if I’m writing a compiler for a new toy language, I’ll write some unit tests for each basic feature of the language. If I’m writing networking code (e.g. a game server), I’ll write some client and server tests that demonstrate valid and invalid packets. These generally fall somewhere between unit and integration tests, but I do them in a unit test style. When the project stabilizes, I’ll go through and rewrite those tests to be narrower in scope, broader in line coverage, and simpler, and keep a few as examples (maybe extract to the readme or something).

              That’s my workflow, and I like knowing that at least part of it is tested. When I mess with stuff, I have a formal step to change the tests as a form of documenting the change I made, and I’ll usually leave extensive comments on the test to describe the relevance.

              Code readability counts, but I don’t think it’s enough. The codebase I work on day to day is quite readable, but it’s very complex since there are hundreds of thousands of lines of code across over a dozen microservices, and there’s a lot of complexity at the boundaries. When I joined the project, I read through a lot of the tests, which was way more helpful to me than reading the code directly. The code describes “how,” but it doesn’t explain “what” or “why.” Tests get into “what” extensively, and “why” can be understood by the types of tests developers choose to write.

              • philm@programming.dev
                link
                fedilink
                arrow-up
                2
                ·
                11 months ago

                For example, if I’m writing a compiler for a new toy language

                Ok, thinking about it (since I wrote a toy language not so long ago), this is probably a perfect example where unit tests make sense almost everywhere (even for prototyping, say parser).

                I think it definitely depends what you’re doing, writing unit tests for prototype graphics (engine) code is no fun (and I see no real benefit).

                Code readability counts, but I don’t think it’s enough.

                I think it depends, For general architecture, E2E or integration tests definitely make sense, for finer-grained code, I think documentation (Rust doc) of the functions in question should be enough to understand what they do (including some examples how to use them, could be tests, often examples (similar as in std rust) in the rust doc are enough IMHO, and otherwise the code itself is the documentation (being able to read code fast is a valuable skill I guess). That obviously doesn’t apply for everything (think about highly theoretical computer science or math code), but yeah it depends…

                • sugar_in_your_tea@sh.itjust.works
                  link
                  fedilink
                  arrow-up
                  2
                  ·
                  11 months ago

                  Yeah, I wouldn’t bother for graphics code either. For that, I want compilable examples, and that’s about it.

                  I do a lot of math and parsers, and that lends itself very well to unit tests.

    • CoderKat@lemm.ee
      link
      fedilink
      English
      arrow-up
      2
      ·
      11 months ago

      Strong typing doesn’t prevent the need for tests. It can certainly catch some issues (and I don’t like dynamically typed languages as a result), but there’s no replacement for unit testing. So much refactoring is only safe because of rigorous test coverage. I can’t begin to tell you how many times a “safe” refactoring actually broke something and it was only thanks to unit tests that I found it.

      If code is doing anything non-trivial, tests are pretty vital for ensuring it works as intended (and for ensuring you don’t write too much code before you realize something doesn’t work). Sure, you can manually test, but often manual testing can have a hard time testing edge cases. And manual testing won’t help you prevent regressions, which is usually the biggest reason to write unit tests. If you have a big, complicated system worked on by more than one person, tests can be critical for ensuring other people (who often have no idea how your code works) don’t break your test. Plus your own future changes.