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-