mth_mad
mth_mad

Reputation: 135

Using mocking with apply R

I am currently mocking in some unit tests, using the packages testthatand mockery. I am trying to understand how the function expect_argsfrom the mockerypackage works when the mocked function is actually called in a function using apply. Here is an example where the test is successful.

myMean <- function(A){
 apply(A,1,mean)
}

myMat = matrix(rep(1,6), nrow = 2, ncol = 3)
test_that("myMean calls base::mean correctly",{
 m <- mock(1, cycle = TRUE)
 with_mock(
 `base::mean` = m,
  myMean(myMat),
  expect_args(m, 1, as.double(myMat[1,])))
})

Let's take now a slightly more complicated example, where the argument of myMeanis actually a data.frame and needs to be converted to a matrix within the function.

myMean <- function(A){
 B = as.matrix(A)
 apply(B,1,mean)
}

myMat = as.data.frame(myMat)
test_that("myMean calls base::mean correctly",{
m <- mock(1, cycle = TRUE)
with_mock(
 `base::mean` = m,
  myMean(myMat),
 expect_args(m, 1, as.double(myMat[1,])))
})

I then get the following error message:

Error: Test failed: 'myMeanSimple calls base::mean correct number of times         
* 1st actual argument not equal to 1st expected argument.
names for target but not for current

This error is explained on the vignette of the mockery package. Nevertheless I do not manage to find which argument name I should associate with as.double(myMat[1,]).

Upvotes: 2

Views: 234

Answers (1)

Lukasz
Lukasz

Reputation: 148

First of all, I'm happy this small utility became useful! Second of all, the error you see results from how your transformations are carried out and how expect_args compares results. Internally, we call expect_equal which requires all of the names of the matrix to be present there.

After calling your second example I run this:

> mock_args(m)
[[1]]
[[1]][[1]]
V1 V2 V3 
 1  1  1 

[[2]]
[[2]][[1]]
V1 V2 V3 
 1  1  1 

So you can see that in the first call a single named raw was passed, and the same is true for the second call - there are names assigned to each column. This is because as.matrix preserves column names. So this is not about argument names, this is about names in the data that's compared.

Now, when you run your final comparison using expect_args you actually use as.double which doesn't preserve names. Thus, the error you see. To fix it you can simply change your expectation to:

expect_args(m, 1, as.matrix(myMat)[1,])

I hope this solves your problem.

Upvotes: 3

Related Questions