Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stubbing out a function called within S3 dispatch #43

Closed
nbenn opened this issue Nov 27, 2020 · 4 comments
Closed

Stubbing out a function called within S3 dispatch #43

nbenn opened this issue Nov 27, 2020 · 4 comments

Comments

@nbenn
Copy link

nbenn commented Nov 27, 2020

I'm running into issues trying to mock a function with S3 dispatch involved. Consider the following setting:

gen <- function(x) UseMethod("gen")

met <- function(x) foo(x)

foo <- function(x) stop("foo")

.S3method("gen", "cls", met)

x <- structure(123, class = "cls")

gen(x)
#> Error in foo(x) : foo

I would now like to be able to call gen(x) is a test where foo() is stubbed out to avoid throwing the error. I assume this is currently not possible using mockery::stub()?

mockery::stub(gen, "foo", "bar", depth = 1)

gen(x)
#> Error in foo(x) : foo

mockery::stub(gen, "foo", "bar", depth = 2)

gen(x)
#> Error in foo(x) : foo

mockery::stub(gen, "foo", "bar", depth = 3)

gen(x)
#> Error in foo(x) : foo

# etc...
@jimhester
Copy link
Member

This limitation doesn't really seem to cause many issues in practice, you usually would mock the generic rather than a method.

@nbenn
Copy link
Author

nbenn commented Dec 11, 2020

Well ok, for whatever reason I was in the situation that I had written some tests using testthat::with_mock() in a scenario like

x <- structure(123, class = "cls")

testthat::with_mock(foo = function(x) "yay!", gen(x))
#> [1] "yay!"

Then I switched to testthat 3e and found that with the current state of things I was not able to do the above using the advertised alternatives. Fine for me if you say this is not in-scope for 'mockery'. I'll close then.

@nbenn nbenn closed this as completed Dec 11, 2020
@MichaelChirico
Copy link
Contributor

MichaelChirico commented Mar 9, 2022

I just ran into this myself. It's not clear how to use mockery to replace with_mock here:

https://github.com/r-lib/lintr/blob/aafba478622c6f43c3fb329c69945c36a4d94b68/tests/testthat/test-ci.R#L47-L49

    with_mock(github_comment = function(x, ...) cat(x, "\n"), .env = asNamespace("lintr"), {
      expect_output(print(l), "*warning:*", fixed = TRUE)
    })

All of the following failed:

foo <- function(x, ...) cat(x, "\n")
mockery::stub(lintr:::print.lints, "github_comment", foo) # lintr:::github_comment executes
mockery::stub(lintr:::print.lints, "github_comment", foo, depth = 2) # error: cannot add bindings to a locked environment
mockery::stub(print, "github_comment", foo, depth = 2L) # weird error "use of NULL environment is defunct"
mockery::stub(print, "github_comment", foo) # lintr:::github_comment executes

@nbenn
Copy link
Author

nbenn commented Mar 11, 2022

@MichaelChirico I started to roll my own, as I was not happy with what {mockery} and {mockr} offered in terms of functionality: {mockthat}. Has worked fine for my own use so far, but I'm sure there are edge-cases, that will break things for my approach too. Happy to take feedback/issues/etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants