views:

151

answers:

1

Below is a class I have written in a web application I am building using Java Google App Engine. I have written Unit Tests using TestNG and all the tests pass. I then run EclEmma in Eclipse to see the test coverage on my code. All the functions show 100% coverage but the file as a whole is showing about 27% coverage. Where is the 73% uncovered code coming from?

Can anyone help me understand how EclEmma works and why I am getting the discrepancy in numbers?

package com.skaxo.sports.models;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable(identityType= IdentityType.APPLICATION)
public class Account {

    @PrimaryKey
    @Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
    private Long id;

    @Persistent
    private String userId;

    @Persistent
    private String firstName;

    @Persistent
    private String lastName;

    @Persistent
    private String email;

    @Persistent
    private boolean termsOfService;

    @Persistent
    private boolean systemEmails;

    public Account() {}

    public Account(String firstName, String lastName, String email) {
     super();
     this.firstName = firstName;
     this.lastName = lastName;
     this.email = email;
    }

    public Account(String userId) {
     super();
     this.userId = userId;
    }

    public void setId(Long id) {
     this.id = id;
    }

    public Long getId() {
     return id;
    }

    public String getUserId() {
     return userId;
    }

    public void setUserId(String userId) {
     this.userId = userId;
    }

    public String getFirstName() {
     return firstName;
    }

    public void setFirstName(String firstName) {
     this.firstName = firstName;
    }

    public String getLastName() {
     return lastName;
    }

    public void setLastName(String lastName) {
     this.lastName = lastName;
    }

    public String getEmail() {
     return email;
    }

    public void setEmail(String email) {
     this.email = email;
    }

    public boolean acceptedTermsOfService() {
     return termsOfService;
    }

    public void setTermsOfService(boolean termsOfService) {
     this.termsOfService = termsOfService;
    }

    public boolean acceptedSystemEmails() {
     return systemEmails;
    }

    public void setSystemEmails(boolean systemEmails) {
     this.systemEmails = systemEmails;
    }
}

Below is the test code for the above class.

package com.skaxo.sports.models;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.assertFalse;

import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

public class AccountTest {

    @Test
    public void testId() {
     Account a = new Account();
     a.setId(1L);
     assertEquals((Long) 1L, a.getId(), "ID");
     a.setId(3L);
     assertNotNull(a.getId(), "The ID is set to null.");
    }

    @Test
    public void testUserId() {
     Account a = new Account();
     a.setUserId("123456ABC");
     assertEquals(a.getUserId(), "123456ABC", "User ID incorrect.");
     a = new Account("123456ABC");
     assertEquals(a.getUserId(), "123456ABC", "User ID incorrect.");
    }

    @Test
    public void testFirstName() {
     Account a = new Account("Test", "User", "[email protected]");
     assertEquals(a.getFirstName(), "Test", 
       "User first name not equal to 'Test'.");
     a.setFirstName("John");
     assertEquals(a.getFirstName(), "John", 
       "User first name not equal to 'John'.");
    }

    @Test
    public void testLastName() {
     Account a = new Account("Test", "User", "[email protected]");
     assertEquals(a.getLastName(), "User",
       "User last name not equal to 'User'.");
     a.setLastName("Doe");
     assertEquals(a.getLastName(), "Doe", 
       "User last name not equal to 'Doe'.");
    }

    @Test
    public void testEmail() {
     Account a = new Account("Test", "User", "[email protected]");
     assertEquals(a.getEmail(), "[email protected]", 
       "User email not equal to '[email protected]'.");
     a.setEmail("[email protected]");
     assertEquals(a.getEmail(), "[email protected]", 
       "User email not equal to '[email protected]'.");
    }

    @Test
    public void testAcceptedTermsOfService() {
     Account a = new Account();
     a.setTermsOfService(true);
     assertTrue(a.acceptedTermsOfService(),
       "Accepted Terms of Service not true.");
     a.setTermsOfService(false);
     assertFalse(a.acceptedTermsOfService(),
       "Accepted Terms of Service not false.");
    }

    @Test
    public void testAcceptedSystemEmails() {
     Account a = new Account();
     a.setSystemEmails(true);
     assertTrue(a.acceptedSystemEmails(), "System Emails is not true.");
     a.setSystemEmails(false);
     assertFalse(a.acceptedSystemEmails(), "System Emails is not false.");
    }
}
+2  A: 

This is a guess, but based on the Javadoc for PersistenceCapable it looks like the class is woven with additional code by the JDO enhancer to implement the interface. If this is the case it is quite possible the additional code is not covered by your tests. If you remove the annotation and run the tests again do you see the expected coverage?

From the Javadoc:

In the Reference Implementation, the JDO Enhancer modifies the class to implement PersistenceCapable prior to loading the class into the runtime environment. The Reference Enhancer also adds code to implement the methods defined by PersistenceCapable.

You could also try using a decompiler like JAD to inspect the compiled class to verify if the class is indeed woven with additional methods at compile time (or as a pre process). Again from the Javadoc:

The extra methods in the PersistenceCapable interface might be generated by pre-processing a .java file, or might be generated from a tool directly. The exact technique for generating the extra methods is not specified by JDO.

Rich Seller
I used JAD and it looks like the jdo code is being inserted into the class. Is there a way to make the test coverage tool not look at this additional code?
Dan
JDO enhancement follows a strict contract ... things start with "jdo". Shouldn't be hard to skip those.
DataNucleus