test-check

2017-01-02T20:08:47.000062Z

Hi. I’ve a question about property based testing and test.check and their suitability to the following integration validation. If I wanted to check that function

(first-available-timeslot {:attendees 3 :starts 2017-02-03 :ends 2017-02-03 :duration 60})
returns the first 1 hour slot not conflicting with a generated set of random meetings in the same calendar. The properties in english would be “result doesn’t overlap with other meetings”, “time slot is in a meeting room with at least a capacity of :attendees" and somehow “the result is the first suitable result. Am I thinking about this the right way?

2017-01-02T20:51:47.000066Z

I assume the function can fail if the constraints aren't satisfiable

2017-01-02T20:53:50.000067Z

Are you planning on just testing with that piece of example data you showed, or generating that input as well?

2017-01-02T20:54:19.000068Z

Correct, and generating input also.

2017-01-02T20:55:02.000069Z

I think the first two properties are good

2017-01-02T20:55:30.000070Z

The third has slightly more of the "duplicating the business logic" flavor

2017-01-02T20:55:55.000071Z

But might be easy enough as to be worth it

2017-01-02T20:56:42.000072Z

okay. I’ll have a bash. My concern was that integration tests are expensive, and having many tests with large datasets even more so, although they obviously offer far more confidence.

2017-01-02T20:57:16.000073Z

Expensive meaning dev time? Waiting for tests?

2017-01-02T20:58:12.000074Z

Waiting for tests. Further, the query might operate against a db, or possibly google calendars api so there’s timeouts and error conditions complicating things.

2017-01-02T20:58:54.000075Z

I would try to mock out things you don't control

2017-01-02T20:59:23.000076Z

Unreliable tests are even more annoying in PBT

2017-01-02T20:59:48.000077Z

Shrinking can be almost meaningless

2017-01-02T21:00:44.000078Z

Yeah, that’s what I was thinking. I actually wonder whether syncing a copy of the calendar into a clojure owned data structure before querying might allow better reasonability. It’s only a small dataset.

2017-01-02T21:01:41.000079Z

Or generate the calendar

2017-01-02T21:03:04.000080Z

A property I just thought of that is a corollary of the "earliest time slot" requirement:

2017-01-02T21:04:28.000081Z

"Given two reservation requests where the first is strictly easier to satisfy than the second, processing them in order should never result in the second being scheduled before the first

2017-01-02T21:05:22.000082Z

Meaning they should have the same date range, and the second should involve at least as many people and minutes

2017-01-02T21:06:12.000083Z

Just parsing that...

2017-01-02T21:06:59.000084Z

Got it, yes. It’s these property identifications that make it difficult, and require a lot of experience.

2017-01-02T21:07:09.000085Z

Yep

2017-01-02T21:08:00.000086Z

I'm about to sacrifice my phone for the sake of providing entertainment to my offspring, so that may be all the pondering I can do for now

2017-01-02T21:08:27.000087Z

@gfredericks thanks for the help. I will explore this further tomorrow and enjoy the rest of your evening!

mattly 2017-01-02T21:37:19.000088Z

is there any way to instrument a set of generators for a test to track performance?

mattly 2017-01-02T21:38:00.000089Z

I've got what, to me, seems like a relatively simple generation set that takes 20+ seconds per iteration for some reason

mattly 2017-01-02T21:38:46.000090Z

there's no recursion, and the only such-that checks that a basic keyword produces something not part of a previously-generated set

mattly 2017-01-02T21:40:56.000091Z

hm

2017-01-02T21:48:00.000092Z

that definitely will slow things down

2017-01-02T21:52:23.000093Z

depending on what you are doing, you could generate a set, then use fmap to remove an element and return a tuple of [removed-element set] to get a similar effect without thrashing such-that

mattly 2017-01-02T22:03:36.000094Z

that could work

mattly 2017-01-02T22:03:54.000095Z

as it is I'm using a modified version of test.chuck's testing that will output things on each iteration

mattly 2017-01-02T22:04:03.000096Z

I'm modifying that to display gen vs. test times

mattly 2017-01-02T22:04:59.000097Z

and then doing simple one-off tests with each of my generators

2017-01-02T22:40:02.000098Z

I doubt thrashing such-that would have such severe consequences unless you manually raised the iteration limit

2017-01-02T22:40:12.000099Z

It gives up after 10 tries

mattly 2017-01-02T22:43:21.000100Z

yeah, it's not that so far as I can tell

mattly 2017-01-02T23:34:47.000101Z

heh, as usual, my takeaway is "don't use generators for things you don't need to test the properties of"

mattly 2017-01-02T23:37:12.000102Z

replacing (gen/map gen/keyword some-other-gen {:min-elements 1 :max-elements 20}) with

2017-01-02T23:40:00.000105Z

🙁

mattly 2017-01-02T23:40:06.000106Z

reduced the time spent running generators to about an eighth of the origional

2017-01-02T23:40:14.000107Z

That's unfortunate

mattly 2017-01-02T23:40:25.000108Z

yeah

2017-01-02T23:40:29.000109Z

But sounds plausible

mattly 2017-01-02T23:41:26.000110Z

the keys don't really have any special properties here, it's mostly, I'm testing the map of some-other-gen here and how that effects the code I'm testing

mattly 2017-01-02T23:41:49.000111Z

but it literally went from

mattly 2017-01-02T23:43:03.000114Z

...this being the output of my runner

mattly 2017-01-02T23:44:34.000115Z

I have another project where I did something similar

mattly 2017-01-02T23:45:01.000116Z

it's a parser of sorts and I needed a bunch of word-looking text

mattly 2017-01-02T23:45:53.000117Z

I started with (gen/not-empty (gen/string-alphanumeric)) and ended up switching to (gen/elements a-set-of-words-from-lorem-text) because it was a similar magnitude faster

mattly 2017-01-02T23:47:43.000118Z

so I've started having to ask on these things, ok, what am I actually testing the properties of here?

mattly 2017-01-02T23:47:56.000119Z

and what can I get away with not generating