Re: [testdrivendevelopment] "bottom-up" TDD and common behaviors

"Brian Marick" <[email protected]> Tue, 3 Dec 2019 17:50:54 -0600
Newsgroups gmane.comp.programming.test-driven-development
Message-ID <[email protected]>
> On Dec 3, 2019, at 6:49 AM, Ron Jeffries <[email protected]> wrote=
:

I hope this makes sense. I have a bad cold, and the old brain is not worki=
ng well.



TL;DR: You gave me the idea that the non-mocking solution to the problem w=
ould be:

1. The `put_updatable_fields` function sets a field that says =E2=80=9Cthi=
s particular structure is known to be updatable=E2=80=9D.
2. We believe the value of that field corresponds to reality because of te=
sts.
3. The tests for the N various functions that return updatable animals jus=
t check that field.

The disadvantage is that I=E2=80=99d still have to arrange that reading an=
 animal returns an animal that `put_updatable_fields` could handle, rather =
than a metaconstant. Not sure how I feel about the tradeoffs.

=3D=3D=3D=3D=3D=3D=3D


> It seems to me that this operation, read and make updatable (maybe form-=
compatible), would properly be a constructor.=20

Yes. I at one point had a variety of structures - they=E2=80=99d be subcla=
sses in a language with inheritance - for different animal use cases. That =
caused various problems that made me decide I wasn=E2=80=99t going to rebel=
 against what (I think) Ecto wants me to do.=20

>=20
> I want a test, probably, for put_updatable_fields, and it needs to check=
 all the fields. Since that takes and returns an animal, it can be tested w=
ith a canned empty animal and a canned full one and an irritating compare e=
qual of some kind. But in mocks, I think it'd be much the same, since we ha=
ve to check each field to see if it has been changed.=20

Yes. I wasn=E2=80=99t explicit, but the two functions called in `updatable=
!` have to be tested in a non-mockish way.=20

>=20
> I guess if I were mocking, then I'd just do the mock thing you show that=
 says that updatable! does in fact call the put. Since I wouldn't likely be=
 mocking (Detroit school, y'know), what would I do? I'd write a test that w=
ould fail if some should-be-updatable field wasn't updatable. (Which I real=
ly think means displayable or something.)

What I=E2=80=99m now calling =E2=80=9Cupdatable=E2=80=9D used to be =E2=80=
=
=9Cshowable=E2=80=9D, but it turns out that what I really mean is =E2=80=
=9Cthe animal structure contains populated fields that can both be shown i=
n a form and that, when changed, provoke an Ecto `update` to generate the r=
ight SQL to update/create the right table rows.=E2=80=9D So =E2=80=9Cupdata=
ble=E2=80=9D was a better reminder.

>=20
> I'm guessing that a non-updatable animal is still a valid animal. (That =
might be a bug.) It appears that updatable is a pure cosmetic thing to get =
the form to work, and that the animal has no reason to know whether it is u=
pdatable. I'm wondering why they aren't always made updatable out of the bo=
x. (Complete Constructor Method). If they were, would that change our think=
ing on how to do this? I think it might: we don't worry any more.

In effect, the four functions are Complete Constructors. What=E2=80=99s re=
ally being tested is that the four Complete Constructors work correctly wit=
h the lower level `Read` code. That code can only fetch on-disk data; there=
 has to be another layer of processing that fills in the fields that don=E2=
=
=80=99t live on disk.=20

In a way, part of the issue here is that Ecto encourages you to have parti=
ally-constructed objects, anathema in the tradition you and I come from.

For example, when you read an `Animal`, you don=E2=80=99t have to read the=
 entire tree of =E2=80=9Cincluded=E2=80=9D (linked by a foreign key) struct=
ures. If you=E2=80=99re reading an animal for a purpose that has nothing to=
 do with ServiceGaps, you can avoid the join and data transfer of that tabl=
e=E2=80=99s data. I=E2=80=99ve chosen not to worry about that - this is a s=
mall app - but you could imagine an app that needed more efficiency.=20

>=20
> Anyway, now we're writing four functions which, I guess? could conceivab=
ly read animals wrongly, not calling updatable! and we want to be sure that=
 they do?
>=20
> Tell the truth, since this is a display issue (?), I think I'd just look=
.

Yes, though there are some complications here. (Forms don=E2=80=99t actual=
ly display Animals, they display Changesets which can include error message=
s associated with the last attempt to process a field, and I find myself an=
noyingly prone to forgetting to add the HTML-generating code to show the er=
ror. Here, for example, is the code that annotates the `name` field with a =
message like `[name] is already taken=E2=80=9D:

     <%=3D text_input(f, :name) %> <%=3D error_tag f, :name %> <br/>

I forgot to add the `error_tag` for the service gap fields.

But what=E2=80=99s needed here is self-discipline and manual testing, not =
error-prevention code. Probably.


> If I worry that someone will try to make these four functions more effic=
ient by removing the updatable bit, though, I need tests.
>=20
> So either A) I'd have only one way to get an animal and it would be upda=
table, end of story I think, or
>=20
> B1) write tests for each of those four functions. Do whatever is_updatab=
le checking one does, one or many fields, etc.=20
> B2) observe duplication and remove it. (def check_is_updatable(animal))?


B2 is the solution I would probably choose, see note at the top of the pag=
e.


-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#35803): https://groups.io/g/testdrivendevelopment/mess=
age/35803
Mute This Topic: https://groups.io/mt/64491946/3268755
Group Owner: [email protected]
Unsubscribe: https://groups.io/g/testdrivendevelopment/leave/6156322/74455=
6386/xyzzy  [[email protected]]
-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-