Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

All of a sudden I am unable to call methods in any classes which are marked with @IsTest. The only thing I changed was all my *-meta.xml files (blindly) from ApiVersion 25/26 to 27.

Until now all my normal apex classes had their test methods in the same file and it was fine, now I suddenly get the error during normal apex code runs (visual force controller):

System.TypeException: Cannot call test methods in non-test context

The only solution is to remove the @IsTest directive. Even removing the testMethods from the class being called does not help.

UPDATE: Reverting back to <apiVersion>26.0</apiVersion> has solved this issue. Any explanation of this?

share|improve this question
    
btw. Reverting back to 26.0 stops the error but it is only by separating code from test classes that you get valid code completion percentages reported under Setup -> Develop -> Apex Classes! –  Marc Feb 18 '13 at 16:15
3  
It is worth noting that with Summer `13 (28.0) you won't be able to include test methods in the class body. They need to be in a dedicated test class. See Apex Test Code Segregation –  Daniel Ballinger Apr 23 '13 at 20:24

3 Answers 3

up vote 5 down vote accepted

That is really strange. So, what you are saying is, you have a class like:

@isTest
public class TestClass{

}

And this class has a method like:

@isTest
public class TestClass{
    public void nonTestMethod(){
    }
}

and when that method is called from a different context, let's say a different public class:

public class NonTestClass{
    public NonTestClass(){
        new TestClass().nonTestMethod();
    }
}

and you are seeing this fail now?

To be honest, that definitely makes sense. As far as I know, it should have always worked like that. Check out the documentation on the @isTest annotation:

Methods of a public test class can only be called from a running test, that is, a test method or code invoked by a test method, and can't be called by a non-test request. In addition, test class methods can be invoked using the Salesforce user interface or the API. For more information, see Running Unit Test Methods.


EDIT: By the way, I would heavily suggest against mixing your test methods and your functional code in the same class. I would highly suggest refactoring your code so that you have two classes, one for the functional and one for the test. For instance, I would have two classes called AccountController and then AccountControllerTest. All of the logic would be contained in AccountController and AccountControllerTest would be marked with the @isTest annotation and only contains testMethods.

There are several good reasons for this, but let me direct you to the Salesforce documentation:

Defining classes of test methods with the isTest annotation

Use the isTest class annotation to define classes that only contain code used for testing your application. If your test methods are contained within their own classes and the Apex class only contains test methods, it is ideal to use the isTest annotation.

Classes defined with the isTest annotation do not count against your organization limit of 2 MB for all Apex code. Classes annotated with isTest must be declared as private. They cannot be interfaces or enums either.

Here is an example of the syntax:

@isTest
private class MyTest {
   // Methods for testing
}

On top of this benefit right out of the box with Salesforce, it makes a good logical break between what is test code and what is functional code. It makes the process of using Test Driven Development (TDD) much easier.

share|improve this answer
    
You have correctly presented what I am seeing but my class is not called TestClass it's more like MyRealClass and it contains public realMethods() and public static testMethod testMethods() The restriction on these classes being private obviously does not apply, ALL my classes are so designated and encapsulate their own test. I find it a neat way of keeping the number of classes down - not for gov limit reasons but sheer sanity. But what you say makes sense and I may split them up in order to conform to the norm. –  Marc Feb 15 '13 at 18:20
    
I'd still like to better understand the proper procedure for upgrading API versions on classes - when, by whom and how should this be done? What is the "proper" API version currently etc. –  Marc Feb 15 '13 at 18:23
    
I can add the discovery that separating test methods out into their own classes fixes the false code completion stats so it seems to be an undocumented (at least in the release notes) Spring 13 restriction. –  Marc Feb 15 '13 at 19:09
    
Excellent points, Jesse! One other thing is that as of the Summer '13 release (API version 28) test methods must be defined in separate classes. blogs.developerforce.com/engineering/2013/04/… –  shadit Apr 19 '13 at 12:19

Hm, this is odd and certainly a regression if what you're saying is accurate. Although not recommended, I've seen a lot of Apex code that has inline test methods in non-test classes.

I was unable to reproduce the issue in the manner you described. I created a class, marked it @IsTest, and made it the controller for a VF page. It had two methods, a public void and a public static testMethod void. Under all versions of the API (for both class and VF page), I was able to directly call both methods from the page.

Curiously, the only way I could reproduce the error you saw was by actually calling the testMethod method from my non-test method. This threw the same error you saw, regardless of API version 25/26/27. This is expected behavior, although I certainly did not expect to be able to call the testMethod directly from my class.

Can you post some code, especially if you can distill the issue down to a simple repro scenario?

In general, it's a good idea to separate your test methods and Salesforce has structured the code size limit in a way that makes it almost compulsory. I get your pain with the fact that Apex (STILL!!!) does not have any support for folder/package structures like pretty much every other language in history, but you get used to having "2 classes per class" in your views.

To answer your question from the comments about when/how to upgrade API versions. I use the "if it ain't broke don't fix it" methodology and rarely upgrade. The main API change over the past couple years that prompted me to upgrade was the @SeeAllData defaulting to false for test methods. As to "how", I just edit the meta.xml files for the classes I want to upgrade. I've never done a blanket up-rev of API version, beca

share|improve this answer
    
Thanks, though I can't provide any code as I've just spent the day separating out my tests from classes. But Jesse's code is the basic gist of it. The only thing you might be missing is API version 27 in your -meta.xml - if you do that you should see an error when you call nonTestMethod() –  Marc Feb 18 '13 at 16:13

To help the rookies who follow, you are no longer allowed to mix testMethods in classes.

The Summer '13 release to API 28 changed this. You used to be able to put your tests anywhere, now you have to use a test class.

https://developer.salesforce.com/blogs/engineering/2013/04/apex-test-code-segregation.html

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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