MangoTheCat / testCoverage

R Code Coverage Package
https://www.mango-solutions.com/blog/analyzing-coverage-of-r-unit-tests-in-packages-the-testcoverage-package
BSD 3-Clause Clear License
33 stars 8 forks source link

problem with flowCore::flowFrame objects #11

Open rogerswt opened 9 years ago

rogerswt commented 9 years ago

First, many thanks for testCoverage. It's the cat's meow!

I'm a heavy user/developer of R for flow cytometry. Most of my code depends on the bioconductor library flowCore. The basic object in flowCore is a flowFrame. I've written testthat tests which run fine, but reportCoverage fails. I suspect it has something to do with the way testCoverage manipulates environments, but I have no real understanding of this.

I've boiled the problem down to something I hope you'll be able to easily reproduce. Here is the code I want to test and analyze for coverage:

#
#  Dummy function.  For coverage testing
#
#2014-12-10  WTR
#

myfunc.mat = function (x) {
  if (is(x, "matrix")) {
    n.elements = nrow(x) * ncol(x)
  } else {
    stop ("not a matrix")
  }

  n.elements
}

myfunc.ff = function (x) {
  if (is(x, "flowFrame")) {
  n.elements = nrow(x) * ncol(x)
  } else {
    stop ("not a flowFrame")
  }

  n.elements
}

There are two nearly identical functions. One takes a matrix as it's sole argument, the other takes a flowFrame.

Here's a testthat test file (which I named testthat_coverage_func.R):

#
#  testthat toy test script.
#   Looking for an issue with flowCore::flowFrame
#
#2014-12-10  WTR
#

library("flowCore")
library("testthat")

context ("TestCoverage")
load ("./testmat.rda")    # instantiates a matrix called 'mat'

test_that ("test.myfunc.mat", {
  expect_equal (nrow(mat), 4)
  expect_equal (ncol(mat), 2)
  expect_equal (colnames(mat), c("FSC-A", "SSC-A"))

})

test_that ("test.myfunc.ff", {
    ff = new("flowFrame", exprs=mat)
    expect_equal (nrow(ff), 4)
    expect_equal (colnames(ff), c("FSC-A", "SSC-A"))
})

Notice that the test for the flowFrame version constructs a new flowFrame from mat, so it's exactly the same data, but stored in a different c4 object.

The rda file was created thus:

> mat = matrix(c(10,20,30,40,11,21,31,41), ncol=2)
> colnames(mat) = c("FSC-A","SSC-A")
> mat
     FSC-A SSC-A
[1,]    10    11
[2,]    20    21
[3,]    30    31
[4,]    40    41
> save (mat, file="testmat.rda")

It runs perfectly fine in testthat:

> test_file ("testthat_coverage_func.R")
TestCoverage : .....

> 

So far, so good. Here's the problem. We load the testCoverage library, the execute the coverage test:

> library(testCoverage)
Loading required package: xtable
Loading required package: tools
Loading required package: rjson
Loading required package: devtools
Loading package testCoverage
 Developed by Mango Solutions <support@mango-solutions.com>.

 It it recomended to restart R after using testCoverage. Either testthat or RUnit must be loaded.

Attaching package: ‘testCoverage’

The following object is masked from ‘package:utils’:

    data

The following objects are masked from ‘package:base’:

    library, require

> reportCoverage (sourcefiles="coverage_func.R", executionfiles="testthat_coverage_func.R", writereport=F)
  1 coverage_func.R ... replacing 20 symbols... setting 6 trace points... 
 Evaluating instrumented code from coverage_func.R in Global Env
 removing 2 trace points for assigning... 
1 : reading testthat_coverage_func.R ...1 testthat_coverage_func.R failed with error
<simpleError: Test failed: 'test.myfunc.ff'
* Not expected: nrow(ff) not equal to 4
names for current but not for target.
* Not expected: colnames(ff) not equal to c("FSC-A", "SSC-A")
Modes: character, NULL
Lengths: 2, 0
target is character, current is NULL.>
$A
                         coverage_func.R
Trace Points                          10
testthat_coverage_func.R               0

$E
[1] TRUE

$B
$B$testthat_coverage_func.R

               coverage_func.R
  Executed                   0
  Not Executed              10

Notice that colnames(ff) is NULL. This is the problem. In the context of testCoverage, we seem to be unsuccessful in handling flowFrame objects.

I hope this gives you a useful test case. Please let me know if I can help further in any way.

Again, thanks for this very important contribution to the field!

All the best, Wade

MangoTheCat commented 9 years ago

@rogerswt Thank you very much for this reproducible example. Issue CCT-70 raised.

rogerswt commented 9 years ago

BTW, should have mentioned: R: 3.1.0 (linux x86_64 kernel 2.6.18-274.3.1.el5.centos.plus) testthat: 0.9.1 testCoverage: 0.1.02 flowCore: 1.30.7

W>

rogerswt commented 9 years ago

Another quick update. I found that testCoverage works fine for another bioconductor package object, a flowFP object from package flowFP.

I made and saved a flowFP object called 'fp'. Added a function to coverage_func.R thus:

myfunc.fp = function (x) {
  require ("flowFP")
  cmat = counts(fp)
  cmat
}

Added a test to testthat_coverage_func.R, and commented out the flowFrame one that failed:

#
#  testthat toy test script.
#   Looking for an issue with flowCore::flowFrame
#
# 2014-12-10  WTR
#

library("flowCore")
library("testthat")

context ("TestCoverage")
load ("./testmat.rda")    # instantiates a matrix called 'mat'
load ("./fp.rda")         # instantiates a flowFP object called 'fp'

test_that ("test.myfunc.mat", {
  expect_equal (nrow(mat), 4)
  expect_equal (ncol(mat), 2)
  expect_equal (colnames(mat), c("FSC-A", "SSC-A"))
  expect_equal (myfunc.mat(mat), 8)

})

# test_that ("test.myfunc.ff", {
#     ff = new("flowFrame", exprs=mat)
#     expect_equal (nrow(ff), 4)
#     expect_equal (colnames(ff), c("FSC-A", "SSC-A"))
# })

test_that ("test.myfunc.fp", {
  expect_equal (ncol(myfunc.fp(fp)), 256)
})

Ran testthat:

> test_file ("testthat_coverage_func.R")
TestCoverage : .....

Ok. Then ran reportCoverage:

> reportCoverage (sourcefiles="coverage_func.R", executionfiles="testthat_coverage_func.R", writereport=T)
  1 coverage_func.R ... replacing 26 symbols... setting 6 trace points... 
 Evaluating instrumented code from coverage_func.R in Global Env
 removing 3 trace points for assigning... 
1 : reading testthat_coverage_func.R ...OK.
Output to /home/rogers/git/R/tools/testdata/coverage_report.html 
$A
                         coverage_func.R
Trace Points                          13
testthat_coverage_func.R               7

$E
[1] FALSE

$B
$B$testthat_coverage_func.R

               coverage_func.R
  Executed                   7
  Not Executed               6

which seems to have worked just fine. So the problem so far seems restricted to the flowFrame object.

Cheers, Wade