shrubbery
shrubbery copied to clipboard
Allow arg values to be given when stubbing
From https://github.com/bguthrie/shrubbery/issues/9#issuecomment-244229067:
Another thing I've been thinking about recently, which is somewhat related (although this may go too far in changing the spirit of shrubbery) is whether we could change the signature of stub entirely to allow arg values to be given when setting up a stubbed function. When the arg values match, the return value would be returned.
Obviously it's possible to use received? afterwards to match/verify args given, but it would be more useful to supply these when subbing IMO.
When we stub a function we typically do care what arg values are given, in some cases we want to return different values based on those arg values. We can verify arg values with received?
but it would be much more convenient (and more powerful) to provide these when stubbing.
Some options for the syntax:
;; 1.
;; Replace the key in the config map with a vector, where the first value
;; denotes the function being stubbed and the subsequent values represent
;; args to be matched.
(stub AProtocol {[:select-user "id1"] user1
[:select-user "id2"] user2})
;; Backwards compatible since we can inspect the key and check if it's a vector.
;; 2.
;; Allow a stubbed function to be added to an existing stub. stub-fn takes the
;; stub as its first arg, the fn to stub as its second, the remaining args are args
;; to match but the last arg is the return value
(-> (stub AProtocol)
(stub-fn :select-user "id1" user1)
(stub-fn :select-user "id2" user2))
;; 3.
;; Replace the current config map with a vector, so that fn names are no longer
;; unique keys. The first value in each vector is the fn to stub, the last is the
;; return value and the values between are the args to match.
(stub AProtocol [[:select-user "id1" user1]
[:select-user "id2" user2]]
;; Backwards compatible since we can inspect the config and check if it's a vector
;; 4.
;; Similar to above, but with a more explicitly descriptive structure
(stub AProtocol [{:fn :select-user :args ["id1"] :return user1}
{:fn :select-user :args ["id2"] :return user2}]
;; Backwards compatible since we can inspect the config and check if it's a vector
I'm not in love with any of these, but I like how terse option 3 is. Feel free to critique these and/or suggest something completely different :)