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
Kenji776Kenji776 

I don't understand testing

Hey everyone,
I just wrote my first apex script today, all it does is autofill some boxes based on information it can pull based on the case number. I am extremely confused, and to be honest, quite angry with this whole testing, code coverage thing. It doesn't make any sense to me at all, I don't need freaking big brother forcing me to error check my code, I'd rather deal with errors than have to put up with this crap. Anyway, I am wondering how I would write the required code to make this test and be able to be deployed.

public class AutoFillPete
{
public static void PETEFILL(PETE_Items__c[] pete)
{
for (PETE_Items__c p:pete)
{
CASE[] contactResult = [SELECT ContactId,AccountId FROM CASE WHERE id = :p.Case__c];
ACCOUNT[] accountResult = [SELECT CID__c FROM ACCOUNT WHERE id = :contactResult[0].AccountId];

if(contactResult.size() > 0)
{
p.Contact__c = contactResult[0].ContactId;
p.Account__c = contactResult[0].AccountId;
p.CID__c = accountResult[0].CID__c;
}
}
}
}

Can someone help me write the code that will be needed to make this deployable (I am still working on sifting through the 14 different guides that are needed to deploy an app to production, I have no idea what I'm doing on that either, something about ant, and such).
mikefmikef
Kenji:

I am sorry to hear that you are "quite angry with the whole testing thing", I hope you are not cousins with Bruce Banner.

Please do not think of testing or Apex test methods as "big brother" watching over you. Think of Apex tests as a way to help keep you code bug and functional issue free.

I have adopted a, write test methods first approach to developing Apex apps. Once I get all my tests ready then it's easy to write the code that does the work. Plus if a test fails I know that I haven't written the correct working code.

I don't advocate this "test first method" of development for all Apex code, if you are writing something small and quick then you don't need this method of writing code.

For your issue a simple test method will do, something like this:

static testMethod void nameOfYourMethod(){
    create an account
    create a contact for the account
    create a case linked to the contact
    test to see if the two were created correctly

    create a PETE_Items__c object that is linked to the case
    use the System.assertEquals() method to test if all the PETE_Items__c fields were filled in correctly
   
}

While you are inside the testMethod() you can create objects just like in normal Apex, Account test = new Account(Name='test'); insert test;
When you are in a testMethod() you are never commiting to the database, or you are never really saving the new record. You are just creating an in memory reference to use for your testing.

Now once the test method is created you can just add it to the AutoFillPete class.
You will have a working test that if you change the main part of the AutoFillPete class you will have a test to run to see if you have broken anything.

On a different note you code will only work for non bulk inserts and updates of the PETE_Items__c object, assuming that you have a trigger on the creation and update of the PETE_Items__c object.
And if a user tries to upate more then one record at a time through the API your code will only update the first PETE_Items__c record.

This is because you have two queries in a for loop, and you are only updating the first record of your PETE_Items__c array.

Hope this helps.

Kenji776Kenji776
Mike,
Thank you for your patient and understand reply. I am sure testing is a good thing, it's just hard to see the positives when you have been so frustrated by failure for the last several hours.

So if I am understanding correctly, a test is almost a copy of your actual code, it just is more... generic, to make sure that things are running correctly?

I am only using this trigger for adding one record, there should never be any time that bulk pete items are being created, that would be awful seeing as Pete items are basically bug reports for developers to work on. For right now I am trying to keep things as simple as possible as I am only just starting to get my legs under me.

Can I just copy and paste that test method you made, right now I am just trying to test my whole process, creation, packaging, deployment, all that, and I would really like some code that just runs right now. If not, thats fine, I can just good with it till it goes, just wanting to know if I should expect errors if I try and slam that in and go.

On a side note, while using ant to try and compile the test samples SF provides, I am getting a login error, for no reason that I can assertain, I am logging in with an admin account, but it says denied. I am sure the username and password are correct as I have copied them from another app that is logging in successuly now.

Thanks for the help, sorry for the angry first post, I just sometimes feel like I'm totally drowning in new technologies, can't keep up, and get frustrated.
mikefmikef
ken:

No worries.

So you are almost there with what a test method is.
It's not a copy of your code, it's what the user does.

A user is going to click on the new button in the app to create a pete item, right?
So we represent that in Apex like this:

PETE_Items__c pete = new PETE_Items__c(name='testPete', LISTING_OUT_ALL_OTHER_FIELDS_THAT_ARE_NEEDED_TO_MAKE_A_PETE);
insert pete:

The line insert pete: will create a new pete record in memory that you can use to test. Page 217 of the apex guide has a lot of examples of test methods, and some stuff you can just use, copy and paste.

On the other note I sometimes struggle with the ant tool kit as well. One thing could be you need a proxy setting, check you browser and make user you don't use a proxy now for web traffic.
Two you are pointing to the wrong end point, make sure in the properties file you point to the correct server.
And three you might have the files in the wrong directory.

If you want create a different post for the ant issue under the apex dev board and attach your properties file and I will have a look.



Kenji776Kenji776
Mike,
Thanks for the info, I'll fool around with it and see what I can come up with.
On the bright side, I managed to get ant to compile the test file, not sure what I do with it now, but oh well, at least it built. By the same token, I'm not real sure how to create my own project for ant to build, bah, I'll figure it out.

I still think this testing is kinda goofy, and am not a fan of it, but hopefully now I can at least write code that will run.
I was so dilusional this morning to think I could just write code, test it and deploy it, that would have been way to easy :P
mikefmikef
Ken if it was easy Oracle would have thought of it first. :)

Kenji776Kenji776
Mike,
Because you've been so helpful, I am wondering if you can maybe point me in the right direction as far as packaging goes.
All I want to do is take this Apex script and trigger I've written in my sandbox, and move it into production. I have spent a good chunk of the day reading, and I have hit a wall. I don't want to put it on the appexchange, which is what every article seems to be about, I just want it in production. How can I do this? Thanks for any help, you can also tell me just to shut up now, and that's fine to, as I know I have been asking alot here. :P Thanks again.
mikefmikef
So you can package the code or you can deploy from Eclipse.

Either way you can get your code into production.

Packaging you will have to create an Appx app in your de org and fill it up with all the code, and dependent objects. Make sure you don't set it to a manage package.

Then register the new app to the appexchange, you will receive a url you can then use this url to add this app to your production org.
This is all done on the private appexchange so unless you give someone the url you are the only person that can deploy this app.

Make sense, and yes I didn't answer everything so you will have to go read a little.

Kenji776Kenji776
Mike,
Alright, thanks for the info. I've heard eclipse mentioned, don't know much about it, but i'll give it a whack. I guess I can't deploy, becuase my script affects a field that is an auto number, and it can't be packages because of that. So hopefully eclipse can do the job.
Kenji776Kenji776
Okay, I've done some work, and I now have figured out how to deploy, and have joined the rest of the development community, and cannot figure out how to actually make my testcode run, or get my % up. I would kill for someone to fix this peice of code for me, cause from there I can copy paste modify my way to glory from here on in.

Here is my apex class (peteautofill.cls)
public class AutoFillPete
{
    public static void PETEFILL(PETE_Items__c[] pete)
    {
        for (PETE_Items__c p:pete)
        {
            CASE[] contactResult = [SELECT ContactId,AccountId FROM CASE WHERE id = :p.Case__c];
            ACCOUNT[] accountResult = [SELECT CID__c FROM ACCOUNT WHERE id = :contactResult[0].AccountId];
           
                 if(contactResult.size() > 0)
              {       
                p.Contact__c = contactResult[0].ContactId;
                p.Account__c = contactResult[0].AccountId;
                p.CID__c = accountResult[0].CID__c;
              }
        }
    }
   
    public static testMethod void AutoFillPete ()
    {
        try
        {
            System.debug('BEGIN\n');
            Account test = new Account(Name='test'); insert test;
            Contact test2 = new Contact(LastName='test'); insert test2;
        }
        catch (DmlException e)
        {
           System.debug(e.getMessage());
        }

    }
}


And here is my trigger (peteautofill.trigger)

trigger peteautofill on PETE_Items__c
(before insert, before update) {
AutoFillPete.PETEFILL(Trigger.new);
}


If I can get even one small thing to deploy correctly, I'll probably be fine from then on, just getting this first project to go is killing me.
Kenji776Kenji776
Okay, I finally got it all figured out. Just for the benefit of any poor sucker like me who is super confused at first by testing, all you are trying to do is programtically reproduce user actions. So in my case, the user clicking a button sends the case number associated with a pete item into my trigger. I needed to programatically recreate that so my function could be tested. In this case, it requires creating a test account, contact, case, and pete item, all linked together. Then I just pass my pete item (that only exists in temporary space) into my actual script that I care about. Below is the working code, I really hope it helps somebody so they don't have to go through the same crap I did. Notice how at the end, the test function calls the main functions with the same type of data being passed that the function would normally expect from a user interaction.

public class AutoFillPete
{
    public static void PETEFILL(PETE_Items__c[] pete)
    {
        for (PETE_Items__c p:pete)
        {
            CASE[] contactResult = [SELECT ContactId,AccountId FROM CASE WHERE id = :p.Case__c];
            ACCOUNT[] accountResult = [SELECT CID__c FROM ACCOUNT WHERE id = :contactResult[0].AccountId];
           
                 if(contactResult.size() > 0)
              {       
                p.Contact__c = contactResult[0].ContactId;
                p.Account__c = contactResult[0].AccountId;
                p.CID__c = accountResult[0].CID__c;
              }
        }
    }
   
    public static testMethod void PETEFILLTEST()
    {

            //Create an account and retreive account #
            Account AccountMake = new Account(Name='test123'); insert AccountMake;   
            ACCOUNT[] getAccountId = [SELECT Id FROM Account WHERE name = 'test123'];
           
            //Create a contact that belongs to the account we just made, and retreive the ID
            Contact ContactMake = new Contact(LastName='testJohnson', AccountId=getAccountId[0].Id); insert ContactMake;
            CONTACT[] getContactId = [SELECT Id FROM Contact WHERE LastName = 'testJohnson'];
           
            //Create a case that belongs to the contact we just made, then fetch it's ID.
            Case CaseMake = new Case(ContactId=getContactId[0].Id, Status='open', Problem__c='Other', Origin='Phone', Subject='testcase21313213', description='test case of joy', PETE_ID__c='ADY2342342' ); insert CaseMake;
            CASE[] getCaseId = [SELECT Id FROM Case WHERE Subject = 'testcase21313213'];
           
            //Create a PETE item, and link it to the case. Then pull it's ID.
            PETE_Items__c PeteMake = new PETE_Items__c(Name='TestItem', Description__c='This is a test', Case__c=getCaseId[0].Id, Present_in_Build__c='2526 (Taxport)', How_to_Reproduce__c='Eat Magic', PETE_ID__c='ADY2342342'); insert PeteMake;           
            PETE_Items__c[] getPeteId = [SELECT Id, Name, Case__c FROM PETE_Items__c WHERE Name = 'TestItem'];

            //Call the main script that autofills those boxes, and pass the array returned from the above query.
             AutoFillPete.PETEFILL(getPETEId);

    }
}
JMPlayer22JMPlayer22

THANK YOU SO MUCH for posting this, Kenji.  It seems like I've been searching forever through the force.com cookbook, help&training, and the online instruction guides for apex...and I understand that it's a somewhat complex task to write apex triggers, but seriously...can't it just be dumbed down?  They did a good job of dumbing down the "hello world" apex trigger that you can write in Salesforce, but it'd be really nice if they'd explain the testing process/requirements using that same SIMPLE trigger.  That Hello World trigger is like crawling and then once they start explaining how to test Apex code you're running a marathon. The examples they give are WAY too advanced for those of us who are just starting out with APEX.  I'm used to using javascript within s-controls...so figuring out how to write the triggers wasn't a big deal...but this testing thing is pretty new to me...and there's basically NO beginner instruction out there for it.  

 

Anyway, I just wanted to say 'thanks' for posting this.  It would've been a lot easier to understand if the guides would've just explained that I'd have to:

 

1. Create a temporary 'fake' record (or fake records) within the test code

2. Call the "functions" of the code within the test code

 

Obviously I don't know all the terminology, but that's because I'm not normally a programmer...I only have a couple programming classes under my belt aside from the stuff I've managed to hack my way through for past work assignments/projects.  I just think it'd be a lot easier for everybody if things were explained more in layman's terms instead of saying "here's an example of how testing works" and then spit out 3 pages of code and expect the reader to know what each piece of the code actually does. 

 

So THANK YOU again for posting your simple example and for explaining it so plainly...right now I've got my trigger in production, but it only has 50% test coverage (2 of 4 lines are covered)...but it's working at least... 

 

If only I could find a post where somebody plainly explains how to increase the coverage on something that's only say...4 lines of code...that would be...pretty basic and simple I'd imagine...

 

 

aaaaaand here's my class:

 

public class MyHelloWorld {

     

public static void addHelloWorld(Account[] accs){

    

      

      for (Account a:accs){

         

         

         if (a.Hello__c != 'World' && a.name=='Testing triggers') {

            a.Hello__c = a.name+' p';

         }

         

         

       }

   }

   

public static testMethod void testdataListCon() {  

 

List<Account> accounts = new List<Account>{};

 

Account a = new Account(Name = 'Testing triggers', Hello__c='');

 

        accounts.add(a);

 

ACCOUNT[] getAccountId = [SELECT Id FROM Account WHERE name = 'Testing triggers' and Hello__c=''];

 

 MyHelloWorld.addHelloWorld(getAccountId);       

 

}//end testmethod

 

JMPlayer22JMPlayer22
Now, I've managed to get what I need done within a trigger and without a class...is there any reason why I would NEED to use classes if I have it working in a trigger?  It's actually in production as a trigger that doesn't reference any classes at all...all the actions I need are within the trigger...