function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
ptepperptepper 

Deploy Bug? Inconsistent unit test results in deployment validation & IDE test runner

Hi,

I'm trying to deploy an Apex class (a Visualforce controller) with the Force.com IDE in Eclipse. When I run my unit tests with the Apex Code test runner, it says I have 76% coverage (17 lines not tested). The code runs fine with no errors and does everything it's supposed to.

But when I go to deploy the code, I get a failure message and a totally different 'Code Coverage' result. Here it says I have 11% coverage (64 lines not tested).

Does anyone know why I would have such drastically different results running the test code from the test runner vs. validating for deployment?  Seems very strange, like a bug.

It also says I have an error which doesn't come up when I save or run the code:

System.QueryException: List has not rows for assignment to SObject.

The line in question is basically:
myObject1 = [select id, name, ... from MyObject__c];

Again, anyone know why this would be happening here but not when I save or run the code?

I'm wondering if there's some bug(s) in the Deploy to Server functionality in Apex. Will I get different results using the Force.com Migration tool?   Anyone had similar problems?

thanks,
-paul
JonPJonP
You are using data from your organization in your test methods.  When you execute your tests in your Sandbox/Developer organization, it works fine because you have a rich data set which you've been using to write your code.  In your production organization, you have different a different data set.

For example, your select statement ("myObject1 = [select id, name, ... from MyObject__c];") assumes you will ALWAYS have exactly one MyObject__c record, and it fails if you have none (and also would fail if there are two or more).  This is a bug in your code that you'll need to fix.

To solve the larger problem of being able to deploy your code to production, you need to write your tests to be environment-neutral, by creating all of the test data you need within your test methods.  DML statements (insert/update/delete) executed within a test method are not committed to the database, so you will not impact your production data by writing tests this way.
ptepperptepper
Jon,

Thanks for the reply. I think I oversimplified my query a bit. It actually has a WHERE clause which specificies the Id of the record. It's more like this:

myObject1 = [select id, name, ... from MyObject__c WHERE id = :id];

and id is taken from a query param of the Visualforce page where the controller is called, so it's only going to try to get that one record.

However, I'm writing my test class so that it creates a page with an ID, something like this:

Code:
PageReference objectEditPgRef = new PageReference('/apex/ObjectEdit?id=a0TT0000000M5vKMAS');
Test.setCurrentPage(objectEditPgRef);

MyObject __c myObj = bew MyObject__c();

MyController ctrl = new MyController(new ApexPages.StandardController(myObj));

But I think your point about creating the data for the object still holds. The problem is, the controller is designed to either load an object from a SOQL query which retrieves the data using the ID from the query parameter, or create a new object (there's an if statement that checks for the presence of the ID & makes a new object if it's null).

I'm already testing it with the null version and creating the object with data in the test - I make the object public and assign it some values, then do whatever DML stuff I need to.

But if, as you're saying, the problem has to do with it using data on the production server when it runs the tests -- maybe the problem is in how I use the ID of an existing record in the sandbox when I create the VF PageReference.

I can try it with the ID of a record that exists on the production server, or create a new object, and get it's ID and submit it with that ID.  but it seems odd that there's such a drastic difference in the coverage because of that alone.  Actually, the Visualforce page that I use in the testing (up there I'm calling it ObjectEdit), doesn't exist on the production server yet - I can't deploy the page until I deploy the controller, but testing the controller seems like it requires the page...

Any ideas? 

Maybe I should be posting this in the VisualForce list?

thanks,
-paul
JonPJonP
Unless your controller is in a package, you should be able to deploy the controller class and the Visualforce page in a single transaction, and the dependencies should all be resolved.  Barring that, you can create an empty stub of your Visualforce page in your production org, then deploy your controller, then deploy your actual VF page over the stub.

As for test data, you definitely should create the record within your test method.  You should never hardcode IDs in test methods, as this inherently makes your tests non-portable and fragile--for example if your test record gets deleted later.
ptepperptepper
Another note -- I refreshed the my sandbox and now the errors I'm getting when I deploy (i.e. from the production server) are the same as the errors I get when I run the test in the sandbox.

The documentation on unit testing is pretty poor, I wish more of these details were in the Apex Language Reference, or in a tutorial somewhere.