Reflections on using Go instead of D

jfondren julian.fondren at gmail.com
Wed Jul 13 07:26:28 UTC 2022


On Wednesday, 13 July 2022 at 05:39:24 UTC, Ola Fosheim Grøstad 
wrote:
>> * Similarly, writing tests in Go, while it's streamlined 
>> similar to how D has `unittest`, the tests themselves can be 
>> quite strainful to write.
>
> In what way? D’s `unittest` does not do much?

In D you have a unittest block, you put some code and assert()s 
in it, you're done. D requires more work if you want some 
features from the test runner (like nicer output than "# modules 
passed unittests" for however many specific tests accomplished, 
or nicer handling of failure).

Go has a more featureful test runner by default, but it doesn't 
have assert(), you need reflect.DeepEqual for cases that would 
just be == in d, you don't have an analog of std.exceptions' 
assertThrown and assertNotThrown. So instead of an instant

```d
unittest {
     assert(f(1) == 2);
}
```

right with your f() definition, you tend to have something like 
this in another file:

```go
func TestF(t *testing.T) {
     want := 2
     got := f(1)
     if want != got {
         t.Errorf("f(1) = %v; wanted %v", got, want)
     }
}
```

and then

```go
func testF(t *testing.T) {
     assert := func(fmt string, want int, got int) {
         if want != got {
             t.Errrof(fmt, got, want)
         }
     }
     assert("f(1) = %v; wanted %v", f(1), 2)
     assert("f(2) = %v; wanted %v", f(2), 3)
}
```

and then maybe you realize that assert() should be calling f() in 
this case so that you can loop over a large range of inputs, so 
you write more of your own test framework code which feels very 
natural to do (and is more work to do).

And actually, this Go is not already not comparable to D as this 
will give you nice messages instead of "file.d(123): [unittest] 
unittest failure" which just tells you what file and line to look 
at. Comparable Go would just be

```go
func TestF(t *testing.T) {
     if f(1) != 2 {
         t.Fail()
     }
}
```

which is *still* providing a readable test name. And after you've 
written all this code, it's just unnatural to not at least use 
t.Errorf()

None of this is a huge chore. Nor is D's super-minimal testing an 
attractive thing to stick with as projects grow vs. switching to 
silly or unit-threaded or the like. But the minimal amount of 
effort demanded to have tests is definitely higher in Go.

The result should be that random Go tests, when you have them, 
are more professional and useful than random D tests, but that 
random D code is more likely to have tests. Certainly if you have 
some trivial single-file utility, Go already needs a second file 
just to have the tests, but with D you can make a #! /usr/bin/env 
dub script that performs its trivial utility function by default 
and then can be called in a special way to run its tests.


More information about the Digitalmars-d mailing list