Fork me on GitHub
#juxt
<
2020-04-17
>
dominicm06:04:41

Maybe it's not necessary to mock the http client, you don't need to test the library. Just swap the middleware out when testing.

jeroenvandijk07:04:13

I’m building my own framework 😎

jeroenvandijk07:04:32

Not for APIs, I’ll leave that to Apex, but for web apps

jeroenvandijk07:04:58

And I would like to use the OpenId code in other places too. I think it’s just better to do it this way

jeroenvandijk07:04:43

I’ll not force my ideas upon others, but I’ll be forced to create my own library as this style of development requires and all-in approach

dominicm07:04:18

I'm not sure what property you're really testing by mocking http though 🤔

jeroenvandijk07:04:47

Yeah long story 🙂

jeroenvandijk07:04:02

If I’m integrating an open Id library into my application, I need to deal with this in my tests. My tests are setup to mock http by using protocols. So I need the library to satisfy these protocols. Swapping middleware is one way, but I think there are better ways

jeroenvandijk07:04:32

Also, where is the openid part in Apex tested?

dominicm07:04:22

I mean from a higher level. There's not much point faking openid interactions when you can bypass them for the purposes of testing. The only reason to mock openid is to ensure the library does what it says. But I doubt you test all your libraries this way.

jeroenvandijk07:04:43

You might be wrong 🙂

jeroenvandijk07:04:56

Anyway, i’m not here to convince anyone

jeroenvandijk07:04:32

Do you know the VCR approach in ruby?

dominicm07:04:38

Haha. I'm now terrified at the idea of you importing all your dependencies' test folders

dominicm07:04:50

I don't, I'm guessing it's like clj-vcr though

jeroenvandijk07:04:45

Haha no I mean, i’m not assuming the libraries are well-tested. So i’m using integration tests to verify it works the way i think it works

jeroenvandijk07:04:05

And I try to make this practical by having a well-tested http layer that runs in memory

jeroenvandijk07:04:17

This includes dns lookups

jeroenvandijk07:04:31

I’m still missing a VCR solution, but I’m getting there

dominicm07:04:46

I wonder if a jvm agent would work for that.

jeroenvandijk07:04:03

Would that work in parallel on the same JVM?

jeroenvandijk07:04:25

I have never tried it. It sounds scary 🙂

dominicm07:04:50

If you were really crazy you'd use a ld preload 😀 that works on any executable.

dominicm07:04:21

Something like sockify pointing at a custom socks5 server would give you total assurance.

jeroenvandijk07:04:46

You think i’m not serious I guess 🙂

dominicm07:04:59

No, I'm not teasing. I actually think sockify is a good idea.

jeroenvandijk07:04:29

Ok I don’t know enough about it. Is it practical though?

dominicm07:04:48

I'm thinking out loud: what other ways you could capture external traffic and transform it.

jeroenvandijk07:04:51

I don’t know, i’ve solved it by using Clojure protocols

dominicm07:04:13

Like, using an LD preload would mean this part of your tests needs to run in a separate JVM. But it would give you a high assurance that nothing is happening without you knowing.

jeroenvandijk07:04:57

I have no idea what LD preload is

jeroenvandijk07:04:31

For me it works to solve it at the Clojure level, that’s also my preference. The thing that I deeply understand

dominicm08:04:23

It's a way to override the function calls being made to the operating system. Eg fstat, fopen, etc

jeroenvandijk08:04:42

Ah yeah that would be super useful for lowlevel programming

jeroenvandijk08:04:14

If you stay at the http layer, things are still simple enough to stay away 😅

dominicm08:04:28

You could also go at the JVM level to set a socks proxy, that would allow you to work at the http layer.

dominicm08:04:24

Then you write a small socks proxy which calls you to say there's a http request, what do you want to do?

jeroenvandijk08:04:32

Why are you telling me to swap middleware and now you are telling me to go to the operating system? :rolling_on_the_floor_laughing:

dominicm08:04:07

Going lower lets you have very holistic control I guess :). Socks is probably the best layer in terms of minimum work & broad coverage.

jeroenvandijk08:04:58

Might be true hehe. But is something I’m not comfortable with (yet). I’m fine in this position

jeroenvandijk08:04:14

I would love to see someone explore this field for me though! I’m not ready yet

jeroenvandijk08:04:57

Btw I feel I have holistic control in my current setup

dominicm08:04:05

I'm exploring this (in words) because I think that adding flags for http clients adds complexity. Given how uncommon the kind of testing you're aiming to do is, I'm trying to think of other ways it could be achieved.

jeroenvandijk08:04:47

I don’t understand why it’s uncommon though

jeroenvandijk08:04:51

In ruby it wasn’t

dominicm08:04:52

Well, it's okay until you use a java library which doesn't support your choice of clojure http client? 😝

jeroenvandijk08:04:08

Yeah that’s sucks, I’ll have to use another library

jeroenvandijk08:04:28

There are a few cases where I have to surrender

dominicm08:04:30

Yeah, that's an interesting question. It might have something to do with global variables perhaps, or maybe just culture. Dunno.

jeroenvandijk08:04:22

I prefer to go the painful route of rewriting something or searching for libraries that fit, than to adapt my way of building applications

jeroenvandijk08:04:27

I can sleep at night 🙂

jeroenvandijk08:04:57

I hope I can convince enough people at some point

dominicm08:04:59

One reason I think VCR is not more popular in Clojure is that Clojure (and other functional languages) work on composition rather than hierarchy.

jeroenvandijk08:04:43

If you build an integration with an external API, what are other ways to properly test this?

jeroenvandijk08:04:00

Does it matter what language you use?

jeroenvandijk08:04:05

I see only one option: scheduled full integration tests + VCR-ed integration test to distinquish internal failures from external failures

jeroenvandijk08:04:16

So let’s we would be building something like let say an openid connector, how can we test this reliably? 😅

dominicm08:04:06

I'd probably test the functions which process the request/result.

dominicm08:04:23

But these are internal tests. Internal to the library.

jeroenvandijk08:04:20

In my experience there are moments when external API’s suddenly change. This moment you want to detect as an external change

jeroenvandijk08:04:44

First problem is detecting is: schedule full integration tests

jeroenvandijk08:04:04

Second problem is knowing that it’s not your code: VCR-ed integration test

jeroenvandijk08:04:37

You could do it with manually processing the request/result, but there is a lot of labour there

jeroenvandijk08:04:02

I still don’t use a VCR approach in Clojure, but I strongly miss it

dominicm08:04:16

That's interesting. These aren't exactly tests you'd run at check-in then?

dominicm08:04:25

You'd run them in production? - and monitor the results conform to some spec at all times?

jeroenvandijk08:04:27

You can run VCR tests anytime. The full integrations tests are too slow and once a day on CI should be fine

jeroenvandijk08:04:18

A long time ago I was working on a service that had integration with Twitter, Facebook etc. We would run full integration tests with real accounts

jeroenvandijk08:04:57

It wasn’t perfect, so we did VCR tests locally and full integrations tests on CI

jeroenvandijk08:04:05

Scheduled would have been better

jeroenvandijk08:04:19

We had many broken builds due to timeouts of the APIs

dominicm08:04:56

Stepping back. Unless you updated your OpenID library / changed your config, you know the failure is external? e.g. the integration tests were fine for 7 days since the last commit and then failed.

jeroenvandijk08:04:29

In a business application, it is very likely that you had many updates in those 7 days

jeroenvandijk08:04:17

I guess the question is whether you are actually working on the openid code or not

jeroenvandijk08:04:44

If the library underneath has these tests, than you don’t have to do it as well

jeroenvandijk08:04:05

But I have never seen this in practise

jeroenvandijk08:04:21

So if your business depends on it, you probably want to do it this way

jeroenvandijk08:04:50

Thanks for challenging me 🙂

jeroenvandijk08:04:01

Need to get some work done now

dominicm08:04:18

Honestly - it's all for me 😀 I want to learn about this testing approach I don't entirely understand!

jeroenvandijk08:04:35

Ok let me finish this framework and you will see it

jeroenvandijk08:04:19

And also watch that presentation. He has similar ideas

jeroenvandijk08:04:50

In an application I try to make everything deterministic. That means: random numbers, http, time and anything that is related

jeroenvandijk08:04:08

It makes live much easier

jeroenvandijk08:04:17

(and your tests faster)

dvingo20:04:52

hello, is this an appropriate channel to inquire about the tick time lib?

dvingo21:04:20

cool, thanks. I am writing specs for some data, and want to validate that some fields are some tick data types, I didn't see any functions in the lib, so I am making my own like so:

(defn date? [d] (= (type d) (type (t/date))))
(comment (date? (t/date)))

(defn date-time? [d] (= (type d) (type (t/date-time))))
just wanted to see if there is some other way to check for these provided in tick

dominicm21:04:08

Right though. You might want to use instance?

dvingo21:04:11

i don't believe the classes are exposed via the api

dvingo21:04:25

ah, i see what you mean

(defn date? [d] (instance? (type (t/date)) d))