There's some value in testing January 15, 2025
That's kind of tongue in cheek, but I am not really one to write tests for my code. Can be subtitled "Man discovers unit tests after 25 years of coding" :P
I'm writing this big project, and it has really turned into a “big project”. At currently 6100 lines of Go code and 40 files, it's definitely not small. I actually wouldn't call it big, and my most recent work project is like 25,000 lines of code. But it's probably the biggest project I've done in Go. I'm starting to see where a decent sized monitor would be helpful! Haha, I've written it on this computer, which I got for playing little PC games while watching sports or something on the couch. It's 14 inches. A tiny baby.
Mostly why I don't really write tests, is that I typically don't find myself doing a lot of stuff that would warrant a test. Unit tests are like, I have this piece of code that is complex and in order to manually test it within the software I'm writing, you would have to go through all of these steps and this condition has to be true, etc, and then I have to verify that this piece of code works. There's two ways to make that faster. #1 is to write a test for it. #2 is to make it easier to get to that place where that code executes. And you can console debug or step through in a debugger.
The other reason I don't really write tests is that the compiler helps with a lot of stuff. I know when something can be null or what bounds something should be, I've been writing code for 28 years or so, including college. I'm set in my ways but I also know and have a ton of experience. The other consideration is to use a good language where it's easy to write good “correct” code. Go is one of those. When you can be told by the compiler or the linter that your code is wrong or there could potentially be an issue, testing becomes more of a burden than an asset.
But what is mostly a pain in this project is what the compiler can't check. In Go, there's the concept of text templates. These are runtime. You have no idea if a change you just made broke a template. And you happily go along writing more code that breaks templates without ever finding out.
I use templates in two instances. One is for rendering the web pages. These are a bit harder to test and I will get to it eventually. But the other place where I use templates is for sending emails. These are much easier to test up front, and are crucial functionality.
The benefit of text templates is that they don't really do anything. There's no complex functionality. They take an object that you pass it, and you can iterate over slices or output field values, do if statements, etc. Very simple and really ensure that nothing catastrophic will happen in them. But if you change a field name or pass it the wrong object, they don't like that.
Go provides the “testing” package for running tests, and you simply create a file like “email_test.go” and write your tests in there, then you can run “go test” and be told if your code is sh@# or not. Or if you broke the templates.
But there's a lot of stuff to testing emails, which is why I went this route. For example, a schedule is sent at the whim of the admin who is entering the schedule. That's just a button click, but only after you've entered all of the users, created a schedule, populated it, made sure that users are allowing email communication, etc. To even properly test the email functionality, you would have to make sure emails are valid, all of the data that is required for the email having useful information (like, specific dates and times and everything), you need to get all of this info from the database and test that it's sending to the right people and with the right information.
Or. And hear me out.
You can just test the templates.
Much easier, and quite valuable. The other stuff, the integration, all of that is Go code, and I'm pretty confident in my ability to set the “Name” field on the email to the “Name” field from the user. And the dates and times fields correctly. Etc. I take a lot of care in writing code, so I am not accidentally setting the Name field to the month name or something. And I'm not accidentally sending the “Invite” email when someone clicks “Email Schedule”. There's just a lot of stuff that would be dumb to write tests for. Hopefully that puts you into my reasoning process of why I don't write tests.
But this is what that looks like
Step 1. Define the tests. I've created a utility struct to hold this info. Basically I'm just defining an email and what templates I need to run. And provide the path to the templates. That struct looks like this:
type emailTest struct {
email interface{}
templates []string
}
Step 2. Run the tests. This is easy and can also be automated on github or something, and report errors to me. That would be cool but right now I'm good with this.
The web pages are much more complex structures, but those are pretty quick to test manually. Plus, it is definitely my common practice to change something everywhere, not just forget that I'm rendering a web page with the same data. Common sense makes up for a lot of testing.
But for uncompiled things, this type of testing is very useful, albeit time consuming! And I like to work fast.
Happy coding!