We are making heavy use of stub and mock objects in our Apex tests. Most of the time we are defining the mocks as inner classes of our test classes. We have noticed, that test classes, which do contain such mock classes do show up at the Overall Code Coverage in the developer console. Such a test class does always have a code coverage of 0% and 0/zz lines covered.

I give a short example. Consider the following class of the business logic:

public virtual class Foo {

    public virtual String doSomething() {
        return anotherFunction('foo');

    public virtual String anotherFunction(String value) {
        return value;

A typical unit test would look like the following:

private class FooTest {

    private class FooMock extends Foo {
        private Boolean anotherFunctionCalled;
        private String value;

        public override String anotherFunction(String value) {
            this.anotherFunctionCalled = true;
            this.value = value;

            return 'test';

    static void testDoSomething() {
        FooMock f = new FooMock();

        String result = f.doSomething();

        System.assertEquals('test', result);
        System.assertEquals(true, f.anotherFunctionCalled);
        System.assertEquals('foo', f.value);

    static void testAnotherFunction() {
        Foo f = new Foo();

        String result = f.anotherFunction('blah');

        System.assertEquals('blah', result);   

The Overall Code Coverage shows the following:

code coverage

Foo: 100% 4/4 Lines covered
FooTest: 0% 0/2 Lines covered

If you click on Apex Classes/Estimate your organization's code coverage you will get the surprising result of 66.67% (4/(2+4)) code coverage, which will not allow you to upload this code as a package.

How can we make sure, that the test classes will not be considered at the coverage estimation?

  • Have you tried adding @isTest to the inner class definition? – Alex Tennant May 6 '14 at 19:00
  • @AlexTennant this results in the following compile error: Error: Compile Error: FooTest.FooMock: Only top-level non-exception class types can be marked as tests at line 5 column 19 – Alexander Johannes May 6 '14 at 19:06
  • I see your problem now, you're subclassing a non-test class. What is your reason for using this approach? – Alex Tennant May 6 '14 at 19:18
  • With this approach we are able to control every aspect of a unit test (e.g. input parameters, calls to other functions and their parameters). Without that approach it would impractical or even impossible to test several aspects of our business logic. For more information see here. – Alexander Johannes May 6 '14 at 19:25
  • I understand the concept. What I wanted to understand was your actual use case. Techniques that work in other environments are not always the best way to go about things in Salesforce due to the limitations of the platform and its architecture. Without knowing your use case it's hard to know if that is true in this case or not. – Alex Tennant May 6 '14 at 19:35

It sounds like you may have a specific problem related to mocking; however, for those experiencing the general problem stated in the question title, "Test classes are included with 0% in overall code coverage calculation", there is another cause for this issue. As @Bujji stated in his answer, it does occur (as of Spring 15) that changing a class from a non-test class to a test class can leave coverage data behind in the org that does not appear to be cleaned up by running all tests or by clearing all test data. I have just experience this issue; in a code base that I inherited, a test utility (factory) class was not marked @isTest, and so was generating coverage - incomplete coverage, in fact. I marked it @isTest, but the class didn't get removed from coverage reporting - it just dropped to 0%, lowering my overall coverage.

Instead of deleting and re-creating the class, you can clean up the old coverage data. The documentation for this known issue (resolved in Spring 15) describes a method for clearing old coverage data which resolves this issue:

1) [experience issue]

2) In the Developer console run this Tooling API query

SELECT Id, ApexClassOrTriggerId, ApexClassOrTrigger.Name,
       NumLinesCovered, NumLinesUncovered 
  FROM ApexCodeCoverageAggregate 

3) Select all results and hit delete

4) Run all tests

If you haven't seen it before, the Query tab of the Developer console has a little "use tooling api" checkbox you'll need to check.

  • I repeated these steps, but no luck. I deleted and recreated the classes with @isTest. – Avinash Aug 10 '16 at 20:02
  • 2
    Helped me to estimate the code coverage correctly as of Winter'17. Thanks! – Artur Jan 18 '17 at 13:36
  • 2) In the Developer console run this Tooling API query SELECT Id, ApexClassOrTriggerId, ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered FROM ApexCodeCoverageAggregate 3) Select all results and hit delete 4) Run all tests This Worked for me as well. Thnx Jason – Robert Thomas Jun 3 '17 at 6:23

I'm guessing you'd want to move the FooMock definition to its own .class file. Keep only @isTest declared methods/classes in your test class file.

Or, perhaps that method needs to be declared static or global?

  • Why would i do that? The mock is only relevant for this particular unit test. This would severly affect the overall number of our classes in a particular project, which is approaching 1000 at the moment (still counting). – Alexander Johannes May 6 '14 at 19:01
  • Most times static is not desired, because it cannot be tested that easily. Global has to be used very carefully in the context of a commercial managed package. – Alexander Johannes May 6 '14 at 19:05
  • 2
    Thank you for your input Alexander I see that Interface classes cannot be Annotated @IsTest. ( developer.salesforce.com/page/… ) So, it appears you do need test methods to cover your mock classes as well. – Dave Eckblad May 6 '14 at 19:46
  • 2
    Yeah, you just need to access f.anotherFunction('bar') from within testDoSomething() and you'll get your two lines of coverage you're missing. – Dave Eckblad May 6 '14 at 19:55
  • @AlexanderJohannes I've encountered this too. It's rather unfortunate. Yes, they should not be top level classes and it makes a mess, but currently the metrics will be skewed unless you do. – Matt and Neil May 6 '14 at 20:02

I finally managed to setup a new DevOrg with the class and test posted in the question.

Screenshot from the DevConsole:

DevConsole Code Coverage

Screenshot from the class overview:

Classes: code coverage

Screenshot from the upload as managed package:

Managed upload result

So, the described problem does not seem to have any real world impact.

  • superb addition to the question/answer. Thanks @Alexander Johannes – Simon Lawrence May 26 '15 at 15:07
  • Your conclusion that "does not seem to have any real world impact"... does that just refer to the fact that you were still able to deploy at 40%? Because from my POV it seems it still has a major impact of only calculating 40% coverage instead of 100%. In a small codebase it seems minor but in a large codebase it would make it pretty difficult to determine what your true coverage is at any given time. – Xtremefaith Jan 30 '17 at 23:02
  • I can only speak for our dev-process, which is no longer affected by this issue. We are aiming and achieving 100% code coverage for each class, so that we barely need to take a look at the overall coverage number. – Alexander Johannes Feb 1 '17 at 8:23

I know this is a late answer but, I would like to give my two cents since I was about to ask a very similar question.

The reason your overall code coverage is so low is due to a non-test method within your test class. The only reason I know is that I had the same exact issue.

A while back our overall code coverage was including test classes with 0% code coverage. So for example, if I had a test class and a class I was covering at 100%, the overall code coverage would show up as 50%.

I went ahead and opened a case for it and it they pointed me to documentation stating that only test methods are allowed in a test class (which is weird since there is an HttpMock example that completely goes against that). I believe they changed it though since:

  1. The documentation that states this no longer exists
  2. The documentation specifies using the @isTest with a utility class as an example now.

More than likely, enough people complained to get this fixed.

Here's the other part of the story.

I was still able to publish, despite my overall code coverage not displaying properly.

Apparently, whenever a deployment occurs, they do not include any classes with the isTest annotation. So we were able to deploy to production, despite the overall code coverage saying it was too low.


Changing the test class from private to public resolved this for me. It no longer showed that the test class needed code coverage.


We implemented the following in a managed package. This gives us testing flexibility.

3 classes MultiRequestMock, TestMultiRequestMock, testHttpCalloutMock


public class MultiRequestMock implements HttpCalloutMock {
Map<String, HttpCalloutMock> requests;

public MultiRequestMock(Map<String, HttpCalloutMock> requests) {
    this.requests = requests;
public HTTPResponse respond(HTTPRequest req) {

    boolean contains = requests.containsKey(req.getEndpoint());
    if (contains == true) {
        HttpCalloutMock mock = requests.get(req.getEndpoint());
        return mock.respond(req);
    } else {
        List<HttpCalloutMock> mocks = requests.values();
        if(mocks.size() > 0){
            return mocks[0].respond(req);
        else {
            return null;


public class TestMultiRequestMock {
public static testmethod void testCallouts() {
    testHttpCalloutMock request1 = new testHttpCalloutMock(200, 'Complete', '[{"Name": "sForceTest1"}]');
    testHttpCalloutMock request2 = new testHttpCalloutMock(200, 'Complete', '[{"LastName": "Test Last Name"}]');

    Map<String, HttpCalloutMock> calloutMap = new Map<String, HttpCalloutMock>();
    calloutMap.put('http://domain1.com', request1);
    system.assertEquals(2, calloutMap.size());

    HttpCalloutMock multiCalloutMock = new MultiRequestMock(calloutMap);

    Test.setMock(HttpCalloutMock.class, multiCalloutMock);
    System.assertEquals('[{"Name": "sForceTest1"}][{"LastName": "Test Last Name"}]',resultTest);
private static String resultTest;
static void multiCalloutTest(){
    Http h1 = new Http();
    Httprequest req1 = new Httprequest();
    HttpResponse res1 = h1.send(req1);

    Http h2 = new Http();
    Httprequest req2 = new Httprequest();
    HttpResponse res2 = h2.send(req2);
    resultTest = res1.getBody()+res2.getBody();


public class testHttpCalloutMock implements HttpCalloutMock{
    protected  Integer code; 
    protected  String status; 
    protected  String body;
    public testHttpCalloutMock(Integer c, String s, String b){
    public HttpResponse respond(HTTPRequest req){
        HttpResponse res = new HttpResponse();
        return res;

I faced similar issue. I was able to fix it by adding "testMethod" keyword to the method.

Instead of this: @isTest static void testDoSomething() { }

Use this: @isTest static void testMethod testDoSomething() { }

  • This makes the problem even worse. If i exchange @isTest with testMethod, the unvovered lines in the test class grow from 0/2 to 0/6. – Alexander Johannes May 21 '14 at 7:24

The Solution for this one is

1.If initially you have created a Controller class(not test class just normal class) and covered the class with some code coverage and later on you have changed that class to Test class using @isTest annotation then that class is treated as test class but code coverage is set to 0% because it's not removing from test coverage reports(Salesforce Issue).

Best Solution : Delete that class (which is converted from class to test class)and create again the same test class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.