I'm trying to set up jacoco for an android project, but there are two issues with the generated report.
1- I declared the destination folder for HTML and XML report but the generated report appears in build/reports/coverage/androidTest/debug
2- the generated report is incorrect and shows that the adder class is not covered, which is wrong.
adder class
class Adder {
fun adder(a:Int,b:Int):Int{
return a+b
}
fun subtractor(a:Int,b:Int):Int{
return a-b
}
}
test class
class AdderTest {
#Test
fun `test`(){
assertEquals(3,Adder().adder(1,2))
}
#Test
fun `substract`(){
assertEquals(-1,Adder().subtractor(1,2))
}
}
jacoco script
apply plugin: 'jacoco'
project.afterEvaluate { project ->
setupAndroidReporting()
}
def setupAndroidReporting() {
tasks.withType(Test) {
// Whether or not classes without source location should be instrumented
jacoco.includeNoLocationClasses = true
jacoco.excludes = ['jdk.internal.*']
}
// Grab all build types and product flavors
def buildTypes = android.buildTypes.collect { type ->
type.name
}
def productFlavors = android.productFlavors.collect { flavor ->
flavor.name
}
// When no product flavors defined, use empty
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
def sourceName, sourcePath
if (!productFlavorName) {
sourceName = sourcePath = "${buildTypeName}"
} else {
sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
sourcePath = "${productFlavorName}/${buildTypeName}"
}
def testTaskName = "test${sourceName.capitalize()}UnitTest"
System.out.println("Task -> $testTaskName")
// Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest'
task "${testTaskName}Coverage1"(type: JacocoReport, dependsOn: "$testTaskName") {
group = "Reporting"
description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
if (buildTypeName == 'debug') {
reports {
csv.enabled true // change if needed
xml.enabled false // change if needed
xml.setDestination(new File("${project.rootDir.path}/coverage-report"))
html {
enabled true
destination new File("${project.rootDir.path}/coverage-report")
}
}
def fileFilter = [
]
def javaTree = fileTree(dir: "${project.buildDir}/intermediates/javac/$sourceName/classes", excludes: fileFilter)
def kotlinTree = fileTree(dir: "${project.buildDir}/tmp/kotlin-classes/$sourceName", excludes: fileFilter)
classDirectories.from = files([javaTree], [kotlinTree])
executionData.from = files("${project.buildDir}/jacoco/${testTaskName}.exec")
def coverageSourceDirs = ["src/main/java",
"src/$productFlavorName/java",
"src/$buildTypeName/java"]
sourceDirectories.setFrom(files(coverageSourceDirs))
additionalSourceDirs.setFrom(files(coverageSourceDirs))
println "xml report: file://${reports.xml.destination}"
println "html report: file://${reports.html.destination}/index.html"
}
}
}
}
}
android {
buildTypes {
debug {
testCoverageEnabled true
}
}
}
report
Related
I have a simple program in Ktor. It runs perfectly, but when I run the unit testing class it only throws this error: "expected:<200 OK> but was:<404 Not Found>"
This is my unit test code:
class ApplicationTest {
#Test
fun testRoot() = testApplication {
val response = client.get("/")
assertEquals(HttpStatusCode.OK, response.status)
}
#Test
fun testStart() = testApplication {
val response = client.post("/start")
assertEquals(HttpStatusCode.OK, response.status)
}
}
This is my Application.kt:
const val enableHTTPS = false
const val portHTTP = 80
const val portHTTPS = 7001
lateinit var environment: ApplicationEngineEnvironment
fun main() {
initEnvironment()
embeddedServer(Netty, environment = environment).start(wait = true)
}
My routing file is:
fun Application.configureRouting() {
routing {
get {
call.respond(ApiDetails())
}
post("/start") {
call.response.status(HttpStatusCode.OK)
}
post("/move") {
val gameDetails: GameDetails = call.receive()
val move = BasicStrategy().move(gameDetails, application)
call.respond(move)
}
post("/end") {
}
}
}
To test an application, its modules should be loaded to testApplication. Loading modules to testApplication depends on the way used to create a server: by using the application.conf configuration file or in code using the embeddedServer function.
If you have the application.conf file in the resources folder, testApplication loads all modules and properties specified in the configuration file automatically.
You can disable loading modules by customizing an environment for tests.
If you use embeddedServer, you can add modules to a test application manually using the application function:
fun testModule1() = testApplication {
application {
module1()
module2()
}
}
In your case:
class ApplicationTest {
#Test
fun testRoot() = testApplication {
application {
configureRouting()
}
environment {
config = MapApplicationConfig(
"ktor.deployment.port" to "80",
"ktor.deployment.sslPort" to "7001"
)
}
val response = client.get("/")
assertEquals(HttpStatusCode.OK, response.status)
}
#Test
fun testStart() = testApplication {
application {
configureRouting()
}
environment {
config = MapApplicationConfig(
"ktor.deployment.port" to "80",
"ktor.deployment.sslPort" to "7001"
)
}
val response = client.post("/start")
assertEquals(HttpStatusCode.OK, response.status)
}
}
Hi guys i am on trouble about getting the current user provided by spring.
Here's my unit test code
void "Test if adding project will sucess"() {
given:
def createProjectMock = mockFor(UserService)
createProjectMock.demand.createNewProject { Map projectMap ->
return true
}
controller.userService = createProjectMock.createMock()
when: "saveProject is execute"
controller.saveProject()
then: "page will to the list to view the saved project"
response.redirectedUrl == '/user/index2'
}
Here's my controller
def saveProject(ProjectActionCommand projectCmd) {
def currentUser = springSecurityService.currentUser
if (projectCmd.hasErrors()) {
render view: 'createProject', model: [projectInstance: projectCmd, user:currentUser]
} else {
def getProjectMap = [:]
getProjectMap = [
projectName: params.projectName,
user: currentUser
]
def saveProject = userService.createNewProject(getProjectMap)
if (saveProject) {
redirect view: 'index2'
} else {
render 'Error upon saving'
}
}
}
And here's my service
Project createNewProject(Map projectMap){
def createProject = new Project()
createProject.with {
projectName = projectMap.projectName
user = projectMap.user
}
createProject.save(failOnError:true, flush: true)
}
And i always getting this error:
Cannot get property 'currentUser' on null object.
Hope you can help me. Thanks
Cannot get property 'currentUser' on null object.
means that you haven't mocked springSecurityService. Let's do it in setup section (I assume it may be useful also in other methods in this class):
def springSecurityService
def setup() {
springSecurityService = Mock(SpringSecurityService)
controller.springSecurityService = springSecurityService
}
At this point your code is going to work. However remember that you can always mock also the actual logged user and test it at any point:
User user = Mock(User)
springSecurityService.currentUser >> user
I have migrated Grails from 1.3.7 to version 2.4.4. And now when I run unit test cases it fails with below reason. There are 45 plus test cases which fail with below exception:
Tests in error:
testEdit(AddressControllerTest): No signature of method: static entity.Address.get() is applicable for argument types: (null) values: [null]
My class name is AddressController.groovy
def edit = {
def quoteInstance = Quote.get( params.id )
if(!quoteInstance) {
flash.message = "Quote not found with id ${params.id}"
redirect(action:list)
}
else {
return [ quoteInstance : quoteInstance ]
}
}
And this is the before method:
#Before
public void setUp() {
super.setUp()
flash = [ : ]
AddressController.metaClass.getFlash= { -> flash }
params = [ : ]
AddressController.metaClass.getParams = { -> params }
redirectParams = [ : ]
AddressController.metaClass.'static'.redirect = { Map args ->
redirectParams = args }
renderParams= [ : ]
AddressController.metaClass.render = { Map args -> renderParams = args }
}
And the actual test case is:
#Test
public void testEdit(){
params['id'] = 123 ;
Quote.metaClass.static.get = { int id ->
assertEquals params.id, id
return null
}
QuoteController cc = new QuoteController()
cc.edit()
assertEquals 'Quote not found with id 123', flash.message
assertEquals cc.list, redirectParams.action
}
I suspect the GUnit jar class might have been change.
I'm using Grails 2.3.8 and trying to create a unit test for a filter that uses a service.
The filter:
class LicenseFilters {
def licenseService
def filters = {
all(controller:'*', action:'*') {
before = {
if(!licenseService.checkLicense()){
redirect(controller:"licenseExpired")
return false
}
}
}
}
}
The spec, first attempt:
#TestFor(ExecutionTraceController)
#Mock(LicenseFilters)
class LicenseFiltersSpec extends Specification{
void "Test filter redirects when license is wrong"() {
given:
LicenseFilters bean=applicationContext.getBean("com.nortia.sgmentia.license.LicenseFilters")
bean.licenseService=this.buildLicenseServiceStub(false)
when:
withFilters(action:"list") {
controller.list()
}
then:
response.redirectedUrl == '/licenseExpired'
}
private LicenseService buildLicenseServiceStub(boolean ok){
LicenseService result=Stub(LicenseService)
result.checkLicense() >> ok
return result
}
}
But it turns out (by debugging) that the bean that I grab from the context it is NOT the same one that receives the request thus I still get a NPE.
In a second attempt I try using defineBeans:
void "Test filter redirects when license is wrong"() {
given:
defineBeans {
licenseService(MethodInvokingFactoryBean){
targetObject = this
targetMethod= "buildLicenseServiceStub"
arguments=[false]
}
}
when:
withFilters(action:"list") {
controller.list()
}
then:
response.redirectedUrl == '/licenseExpired'
}
But the mocked bean is neither bean instanciated nor inyected.
Should I try to inyect the service manually into the filter??
There was this issue https://jira.grails.org/browse/GRAILS-8976 but it is closed.
I came across a similar situation and was able to fix it by adding the service to the #Mock annotation, i.e. #Mock([LicenseFilters, LicenseService]).
In your case the spec would look something like the following:
#TestFor(ExecutionTraceController)
#Mock([LicenseFilters, LicenseService])
class LicenseFiltersSpec extends Specification {
void "Test filter redirects when license is wrong"() {
given:
defineBeans {
licenseService(MethodInvokingFactoryBean) {
targetObject = this
targetMethod = "buildLicenseServiceStub"
arguments = [false]
}
}
when:
withFilters(action: "list") {
controller.list()
}
then:
response.redirectedUrl == '/licenseExpired'
}
private LicenseService buildLicenseServiceStub(boolean ok) {
LicenseService result = Stub(LicenseService)
result.checkLicense() >> ok
return result
}
}
Note: that mocking the service in this manner will, by default, inject an instance of the actual LicenseService into your filter. So, if the above defineBeans block is removed the actual implementation of LicenseService.checkLicense() will be called.
I finally found a workaround to make it work going with the second approach (using defineBeans).
The service is not being autowired into the filter so I finally did it manually with a pseudo-singleton:
class LicenseFilters {
def licenseService
def filters = {
all(controller:'*', action:'*') {
before = {
if(!this.licenseService){
this.licenseService=applicationContext.getBean("licenseService")
}
if(!this.licenseService.checkLicense()){
redirect(controller:"licenseExpired")
return false
}
}
}
}
}
Quite ugly but a solution at least.
Hope it helps someone out there.
I am updating unit tests in a Grails project. We were originally using version 1.3.9 and now we are updating to version 2.3.9. I am using Spock.
I keep getting this error:
results:
junit.framework.AssertionFailedError: Condition not satisfied:
controller.edit() == [filterCategoryInstance: filterCategoryInstance]
| | | |
| null false John
com.xxxxxx.xxxxx.FilterCategoryController#20574000
Here is the controller code:
#Secured(["hasAnyRole('CM_ADMIN')"])
def edit() {
def filterCategoryInstance = FilterCategory.get(params.id)
if (!filterCategoryInstance) {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'dpFilterCategory.label', default: 'FilterCategory'), params.id])}"
redirect(action: "list")
}
else {
return [filterCategoryInstance: filterCategoryInstance]
}
}
and here is the test code:
#Mock([FilterCategory, FilterCategoryTag])
#TestFor(FilterCategoryController)
#TestMixin(DomainClassUnitTestMixin)
class FilterCategoryControllerSpec extends ExtendedControllerSpec {
def 'edit action: existing FilterCategory'() {
setup:
mockI18N(FilterCategoryController)
params.id = filterCategoryInstance.id
expect:
controller.edit() == [filterCategoryInstance: filterCategoryInstance]
where:
tag = new FilterCategoryTag(name: 'tag1')
filterCategoryInstance = new FilterCategory(name: "John",
submissionText:"John", sortOrder:0, 'filterCategoryTags': [tag])
}
And here is the ExtendedControllerSpec code. I hope I have included enough code:
I have looked at the following web pages for guidance:
#Mixin(MetaClassMixin)
class ExtendedControllerSpec extends Specification {
def props
protected void setup() {
//super.setup()
props = new Properties()
File file = new File("grails-app/i18n/messages.properties")
if (file.exists()) {
def stream = new FileInputStream(file)
props.load stream
stream.close()
}
mockI18N(controller)
}
def mockI18N = { controller ->
controller.metaClass.message = { Map map ->
if (!map.code)
return ""
if (map.args) {
def formatter = new MessageFormat("")
if (props.getProperty(map.code)) {
formatter.applyPattern props.getProperty(map.code)
}
return formatter.format(map.args.toArray())
} else {
if (props && props.hasProperty(map.code)) {
return props.getProperty(map.code)
} else {
return map.code
}
}
}
}
/**
* add dynamic methods in test setup.
*/
protected void addDynamicMethods() {
registerMetaClass(String)
String.metaClass.mixin StringUtils
}
protected GrailsUser mockGrailsUser() {
return Mock(GrailsUser)
}
...
/**
* must call AFTER mockDpSercurityService
*/
protected void setHasRoleTrue() {
if (controller?.dpSecurityService?.metaClass) {
controller.dpSecurityService.metaClass.hasRole = {return true}
}
}
protected void setHasRoleFalse() {
if (controller?.dpSecurityService?.metaClass) {
controller.dpSecurityService.metaClass.hasRole = {return false}
}
}
protected void mockUserService() {
controller.dpUserService = new MockFor(UserService)
}
}
http://sanjaykanwar.blogspot.com/2012/07/grails-controller-test-with-spock.html
http://naleid.com/blog/2012/05/01/upgrading-to-grails-2-unit-testing
Looks like the if branch gets executed in edit() instead of the else branch because FilterCategory does not get saved and therfore does not get a proper id.