Skip to content
Browse files

introduce mock passthrough

  • Loading branch information...
1 parent 2d0f57d commit 9e719cbed9abccf81faeed8ccb3e5c7280007ad4 @sigma committed Mar 10, 2012
Showing with 65 additions and 11 deletions.
  1. +21 −0 README.markdown
  2. +17 −0 mocker-tests.el
  3. +27 −11 mocker.el
21 README.markdown
@@ -106,6 +106,8 @@ Each record definition actually builds a `mocker-record` object, that's
responsible for checking the actual behavior. By providing alternative
implementations of those records, one can adapt the mocking to special needs.
+### Stubs
As a quick proof of concept, an implementation of a stub is provided with the
class `mocker-stub-record` which casualy ignores any input and always emits the
same output:
@@ -116,6 +118,25 @@ same output:
(foo 12345))
+### Passthrough
+In some occasions, you might want to mock only some calls for a function, and
+let other calls invoke the real one. This can be achieved by using the
+`mocker-passthrough-record`. In the following example, the first call to
+`ignore` uses the real implementation, while the second one is mocked to return
+(mocker-let ((ignore (x)
+ :records ((:record-cls mocker-passthrough-record
+ :input '(42))
+ (:input '(58) :output t))))
+ (or (ignore 42)
+ (ignore 58)))
+### Provide your own
Customized classes can be provided, that can even introduce a mini-language for
describing the stub. This can be achieved by overloading
`mocker-read-record` correctly.
17 mocker-tests.el
@@ -183,5 +183,22 @@
(foo 1 2 3)
(bar 42))))))
+(ert-deftest mocker-passthrough-basic ()
+ (should
+ (not
+ (mocker-let ((ignore (x)
+ :records ((:record-cls mocker-passthrough-record
+ :input '(42)))))
+ (ignore 42)))))
+(ert-deftest mocker-passthrough-mixed ()
+ (should
+ (mocker-let ((ignore (x)
+ :records ((:record-cls mocker-passthrough-record
+ :input '(42))
+ (:input '(58) :output t))))
+ (or (ignore 42)
+ (ignore 58)))))
(provide 'mocker-tests)
;;; mocker-tests.el ends here
38 mocker.el
@@ -51,13 +51,16 @@
;;; Mock object
(defclass mocker-mock ()
((function :initarg :function :type symbol)
+ (orig-def :initarg :orig-def :initform nil)
(argspec :initarg :argspec :initform nil :type list)
(ordered :initarg :ordered :initform t)
(records :initarg :records :initform nil :type list)))
(defmethod constructor :static ((mock mocker-mock) newname &rest args)
(let* ((obj (call-next-method))
- (recs (oref obj :records)))
+ (recs (oref obj :records))
+ (func (oref obj :function)))
+ (oset obj :orig-def (when (fboundp func) (symbol-function func)))
(oset obj :records nil)
(mapc #'(lambda (r)
(apply 'mocker-add-record obj r))
@@ -176,14 +179,12 @@
(mocker-get-record-expectations rec)
-;;; Mock record default object
-(defclass mocker-record (mocker-record-base)
+;;; Mock input recognizer
+(defclass mocker-input-record (mocker-record-base)
((input :initarg :input :initform nil :type list)
- (output :initarg :output :initform nil)
- (input-matcher :initarg :input-matcher :initform nil)
- (output-generator :initarg :output-generator :initform nil)))
+ (input-matcher :initarg :input-matcher :initform nil)))
-(defmethod constructor :static ((rec mocker-record) newname &rest args)
+(defmethod constructor :static ((rec mocker-input-record) newname &rest args)
(let* ((obj (call-next-method)))
(when (or (not (slot-boundp obj :max-occur))
(and (oref obj :max-occur)
@@ -192,14 +193,22 @@
(oset obj :max-occur (oref obj :min-occur)))
-(defmethod mocker-test-record ((rec mocker-record) args)
+(defmethod mocker-test-record ((rec mocker-input-record) args)
(let ((matcher (oref rec :input-matcher))
(input (oref rec :input)))
(cond (matcher
(apply matcher args))
(equal input args)))))
+(defmethod mocker-get-record-expectations ((rec mocker-input-record))
+ (format "`%s'" (or (oref rec :input-matcher) (oref rec :input))))
+;;; Mock record default object
+(defclass mocker-record (mocker-input-record)
+ ((output :initarg :output :initform nil)
+ (output-generator :initarg :output-generator :initform nil)))
(defmethod mocker-run-record ((rec mocker-record) args)
(let ((generator (oref rec :output-generator))
(output (oref rec :output)))
@@ -208,9 +217,6 @@
-(defmethod mocker-get-record-expectations ((rec mocker-record))
- (format "`%s'" (or (oref rec :input-matcher) (oref rec :input))))
;;; Mock simple stub object
(defclass mocker-stub-record (mocker-record-base)
((output :initarg :output :initform nil)))
@@ -232,6 +238,16 @@
(defmethod mocker-get-record-expectations ((rec mocker-stub-record))
+;;; Mock passthrough record
+(defclass mocker-passthrough-record (mocker-input-record)
+ ())
+(defmethod mocker-run-record ((rec mocker-passthrough-record) args)
+ (let* ((mock (oref rec :-mock))
+ (def (oref mock :orig-def)))
+ (when def
+ (apply def args))))
;;; Helpers
(defun mocker-gen-mocks (mockspecs)
"helper to generate mocks from the input of `mocker-let'"

0 comments on commit 9e719cb

Please sign in to comment.
Something went wrong with that request. Please try again.