I've made some changes and responded to Serge's comments where appropriate on GitHub. Here's a response to Perry:
But I'm curious to know if it was your intention to allow the plugin and the TransformClass to be both coupled to each other (as in the pipe_task framework), and uncoupled (as in the testTransform.py tests). Same comment about the relationship between the field name which is given as the "name" argument on construction of the Transform, and the name of the plugin. They seem to be uncoupled in the same way.
Right, good question.
The expectation is that there is a single, well defined transform which is appropriate for the results of a particular measurement. Thus, there is a tight coupling from measurement algorithm to transformation.
This is not true in reverse: a given transform may be applicable to the results of more than one measurement. For example, a simple conversion of flux to magnitude could be appropriate for a bunch of different flux measurements.
However, even though in production I think there should always be a link from a given measurement to its associated transform, that's not always the case in testing: it's much easier to write good tests for things if they can be broken down into the smallest possible pieces, which is what I tried to do here.
I'm not sure why NullTransform is the default for getTransformClass().
Serge raised the same question; I've changed it to PassThroughTransform.
why doesn't the testPassThroughTransform do field value tests?
Good question. It does now.
Does the fact that the calib argument of the transform operator has to be constructed even if it is not used indicate that it should be an optional parameter?
Considering the transform stand-alone, I think that's true – things like Null or PassThrough clearly don't need a WCS and calibration. But the task interface will always provide those arguments, and I don't think that (outside test cases) the transforms will usually be accessed in other ways, so I'm not sure the flexibility is necessary; I tend to prefer less code and a rigid interface unless we actually have a good reason to do something else.
Thanks to both of you for the helpful comments!