Showing posts with label unit test. Show all posts
Showing posts with label unit test. Show all posts

Wednesday, April 5, 2017

Real Business Data Returns

Auntie Pat Tern believes you can have your cake and eat it too, "Just use your resources wisely". So I wanted to see how to use my static resources more wisely in my Salesforce org. I have previously shown how to use static resources for test data. Now, I want to use that same data in developer sandboxes created from my org.  Since static resources are brought over like code to developer sandboxes, I can reference them in code I execute when I generate the sandboxes. Using the map datatype helps me keep relationships intact as well:

With this simple trick, I can preload my dev orgs with sample business data that I am using in my unit tests. Like Auntie Pat Tern promised, I can have my cake and eat it too when it comes to using realistic sample data in my tests and development orgs.

Sunday, August 7, 2016

CSV Data: Commonly Surfacing Vexations in Data

According to Auntie Pat Tern, "Trying the same thing over and over without getting the results you want is enough to make anyone crazy." Unfortunately, that's the excuse Tim Toady uses when he doesn't do his homework because he's tired of not getting the results he wants from the effort.

When it comes to creating CSV files for use as unit test data, what should be an easy process can make you a bit crazy if you wind up getting unfamiliar errors. The following steps and potential errors may help:

Step 1: Export some production data.
Step 2: Delete all but a reasonable selection of data.
Step 3: Remove system fields.
Step 4: Make sure the date fields are in the form YYYY-MM-DD
Step 5: Make sure date/time fields have a "T" between the date and time, with no space, such as 2016-08-07T01:40:39
Step 6: Make sure the commas that appear in text fields haven't thrown off the number of columns.
Step 7: Make sure there are no blank rows with only commas and no values
Step 8: Renumber IDs starting with 1
Step 9: Remove any invalid IDs for related records (Account ID of 000000000000000AAA appears for all top-level accounts, and should be removed, for example)
Step 10: Upload the CSV file as a Static Resource for your code to reference

If you are creating a set of child records for an object that is related to another object, you can sort the parent and child data by the IDs of the parent to make sure you get records that match in both data sets. Use search and replace to redo the parent IDs to match the new IDs in the CSV file of parent records. For example, if you have a CSV for Accounts with IDs numbered 1-200, the related contact records must use 1-200 for the Account ID as well.

Bad CSV files might result in the following errors:

Potential Error Likely Solution
Invalid ID value on line 2: 000000000000000 Remove invalid IDs
Too many DML rows: 10001 Load fewer records
CSV Parse error: '8/20/1959' is not a valid value for the type xsd:date Format dates as YYYY-MM-DD
Duplicate ID value on line 81: null Remove empty rows from CSV file
CSV Parse error: '2011-09-07 01:00:31' is not a valid value for the type xsd:dateTime Format date/time fields with "T" rather than space between date and time
Validation Errors While Saving Record(s) Erroneous data or IDs not starting with 1
System.UnexpectedException: Salesforce System Error Remove stray commas throwing off columns
Static Resource not found Make sure code refers to Static Resource by name

Start with a small number of records using the fewest fields for testing the code or configuration changes you need to test. That way, you won't wind up like Tim Toady, who falls back on bad habits when errors occur with his first attempts to follow best practices.

Sunday, July 31, 2016

What A Load Of Business Data

Auntie Pat Tern thinks Superman's x-ray vision is stupid because "how would he ever know where he's supposed to look and where he should not bother focusing?" That got me wondering about the data and tests in my Salesforce org.  Even clicks-not-code developers should have automated tests that validate configuration changes with existing and expected data. So what's the best way to know which data those automated tests should use?

Some Salesforce developers like to write automated tests with "SeeAllData=True", an outdated and bad practice. A test that can see all data is not the same as a test that is smart enough to see the data that needs testing. For example, a good test will test positive scenarios, negative scenarios and extremes. In other words:
  • What if the data is exactly what we planned for -- records with all the right data in all the right places?
  • What if the data falls outside of expected norms -- records with missing fields or invalid data, for example?
  • What if the data is coming in from a data import operation or an integration and many records need to be processed?
Admins can follow a few simple steps to create automated tests to run against their configuration changes, and their efforts can be used by developers for better unit tests as well. Simply create sample data representative of the expected inputs. Then use code like the following to load that data in a unit test:


Note that you will want to use data that corresponds to the configuration changes that you are testing. In this example, configuration changes and business process automation around Account, Contact and Opportunity record creation will be tested. You can create a similar test class for other related objects, including custom objects.

This code can be run as a unit test by itself to validate configuration changes, or it can be called by other test code to set up data for more complex unit testing related to other code in the org.

Next week, I will look into some of the errors that might occur when you create CSV files of sample data and how to avoid those errors.

But for now, Auntie Pat Tern has a point, who wants Superman looking at just any old thing with his x-ray vision when he ought to be focusing on information that's most helpful.

Tuesday, May 17, 2016

SeeAllData = Fail

According to Auntie Pat Tern, it takes 21 days to break a bad habit, but Salesforce developers have had about that many API versions to break the bad habit of writing unit tests with "SeeAllData=true".

In most cases, this clause alone can render tests completely useless. Unit tests should prove that code functions according to specifications by asserting proper database manipulations--create, read, update, delete operations--as well as Visualforce navigation.

I looked at unit tests in my org and found this example of a test that failed to achieve its purpose:

This test should be asserting that the data for ordering samples can be created with just a contact and sample type defined.  Unfortunately the test relies on existing, live, org data rather than test 'silo' data because of "SeeAllData=true" in the first line. There are easy methods for unit tests to create their own test data without relying on live org data.

We encountered the following problems because of using "SeeAllData=true":
  • It required us to maintain test data among our real data.
  • When the test data was changed during data cleanup (in one case, Pat Tern's Account was deleted), the tests failed even though functionality was unchanged.
  • Tests were not reliable between Sandboxes and Production orgs due to data differences rather than actual functionality.
  • Apex Hammer Tests may not have been automatically monitored in our org for each Salesforce release since Hammer Tests are blind to live org data.
In the rare case where a specific piece of data may be required for your code to behave, consider using custom metadata types instead of Salesforce objects. Trailhead can help you learn more about how they allow you to move metadata and records between orgs and test functionality without needing to see all data in the org.

Saturday, May 7, 2016

Pay Down That Technical Debt

Auntie Pat Tern says we should pay with cash, or at least pay our credit cards off every month because "debt," she says, "is like fresh fish, it seems great at first but gets old fast and then it really stinks."

It's Hammer Time!
So I looked at my Salesforce org to assess the level of technical debt we had accrued and to plan how we would start paying down that debt.

Sometimes technical debt comprises the shortcuts or mistakes that no one has time to correct when a project needs to be completed. Technical debt also develops over time.  As businesses mature and change, their technical solutions can fall behind and create technical debt.

A Salesforce org can be especially prone to this since Salesforce offers a wealth of new features for all orgs three times each year and not all companies make an effort to rewrite their technical solutions based on these new features. Luckily, Salesforce offers some tools to help us assess some of the technical debt associated with our code.

First, I checked our Hammer Test Status.  The data silo gauge revealed that we still had old (and sadly a few new) unit tests that were using "seealldata=true", which we needed to update.  It also revealed a couple of tests that were failing and so needed some attention.

Next I checked the API version on our Apex Classes.  Any class that is 10 or more versions behind the current API version needed a review, both on the code side and on the process side.

The third step for me was reviewing our org's documentation for outdated information on our code.

My org review also included configuration, managed packages and basic processes, as well.

We may not be able to pay down all of our technical debt right away, but a monthly review and reminder of how it accumulates will help us develop better in the future.  And as Auntie Pat Tern says, "It's not just pay me now or pay me later, you know.  It's pay me now or pay me later with additional compounded interest!"

Tuesday, July 14, 2015

Agree on Guidelines Before Adding Code

Remember how your high school and college research papers were graded partly on niggling formatting concerns?  The point was to make sure we all used ibid, idem, op. cit. and loc. cit. correctly.  By getting us all following the same style, the teacher had an easier job understanding our work and we learned to better understand the work of others.  These are the same reason you should define code guidelines for your Salesforce org.
A good style guide provides grounding
without weighing you down.

Whether you are a Salesforce Administrator who works with vendors for your development needs or an in-house developer yourself, documenting basic code style and guidelines for your org should be considered a must.  Code guidelines help ensure that the code can be maintained for years to come and that the org is well documented down to the code level so that admins and developers alike have a thorough understanding of what takes place in the org.

A lot of Apex programmers start with the Google Java Style Guide, which is a great starting point, but you may want to create something brief to share among everyone writing code for your org.  Here are some suggestions for a brief Apex Style Guide:

Style

  1. Avoid unnecessary whitespace.  Whitespace is helpful for indicated blocks of code, using indentations at the beginnings of lines or blank lines before methods, for example.  But whitespace inside of lines of code adds to maintenance time.
  2. Use tab rather than spaces for indenting lines of code to ensure they line up properly and reduce character count.  Indent lines of code within a method by one level from the method.  Indent the code contained by a loop by one level from the line that sets up the loop, for example.
  3. Limit code to 100 columns wide, even in comments so that it can be read without scrolling.
  4. Break SOQL statements into multiple lines with new lines for each clause: From, Where, Order By, etc.  Selected fields should be listed in ascending alphabetical order.

  5.   Map<id,account> aMap = new Map<id,account>([SELECT Id,Name 
                                                  FROM Account 
                                                  LIMIT 50000]);

  6. Comments should appear at the beginning of every class and at the beginning of every method in block format (/* */).  
  7. At the beginning of each class, comments should
    • describe purpose and list related files (classes, triggers, components, VF pages, etc either called by or that will be calling this file) as well as HTTP services called, if any
    • list author name(s) and creation date
    • include modification dates and authors and purpose of modifications
    • list business processes in order they are addressed in the code as a brief summary of methods.
  8. At the beginning of each method, comments should
    • Describe purpose and detail parameters and returned values.
  9. Trigger logic should be contained in at least two files: the Trigger and the Handler(s) containing the business logic.
  10. All code should be ‘bulkified’ to avoid exceeding governor limits when multiple records are processed, at the very least, SOQL and DML statements should only appear outside of loops.

Naming Conventions

  1. File names should begin with a Primary sObject name, followed by a description of the action the code performs, followed by the type of class (eg. Controller, Extension, Helper, Utility, Test, Trigger).  For example, you might have the AccountAddressUpdate Visualforce page and the AccountAddressUpdateExtension controller extension.
  2. Avoid spaces and underscores in file, class, method and variable names.  Also avoid abbreviations when possible.  
  3. Method names begin with a lowercase verb.
  4. Classes should use camel case (eg. CamelCase) while Methods and Variables should use nerd case (eg. modifiedCamelCase).  You could have a controller extension class called AccountAddressUpdateExtension with method updateAddress and variable newStreet, as an example.
  5. Use all caps for constants such as MAXIMUM and MINIMUM.  Constants should be placed after the class header comments and before the first method and method header comments so they can be easily located and updated.
  6. Append “Test” to the class name for all test classes.  For example, the class AccountAddressUpdateExtension would have a corresponding AccountAddressUpdateExtensionTest. 
  7. Collection variables should be plural or otherwise represent the fact that they represent a collection (eg. recordMap, newAccountMap).

Deployment

  1. Remove System.debug statements before pushing code to production.
  2. Require positive and negative scenarios in unit tests using assertions that are clear. 
  3. Salesforce defines minimum code coverage as 75% but we prefer minimum code coverage of 90%.

Fundamentals

  1. For integrations, employ a 'single source of truth' model where possible—data should be stored in one location and referenced by other systems or pulled on an as needed basis only. A redundant system should be created for backup purposes, but should not be used as a data source except in the event of failure recovery. 
  2. Follow the rule of 3 and the abstraction principle. If the same code is used 3 or more times, it needs to be implemented as a reusable class, method or loop. Programmers sometimes refer to this as DRY v WET : "Don’t Repeat Yourself" vs "We Enjoy Typing"). Create abstract code for reusable procedures.

Saturday, November 22, 2014

Learning Coding Skills May Be Easier Than You Think

Last week, I tried to convince you how easy the path can be from Salesforce Administrator to developer.  This week, I'd like to look at a couple of additional resources for the administrator who is beginning to dabble in code.

Don't be afraid to step out of your comfort zone and
try new skills.  You may be better than you think.
As I've mentioned before, Flow, or Visual Workflow, is a lot like a visual programming tool in the ways that it can be used to add complex functionality and alter the Salesforce user interface just by clicking on various programmatic elements.

But you can make Flows even more impactful by employing Visualforce as well.  With Visualforce, you can further customize the user interface and even incorporate HTML, CSS and JavaScript to provide more bells and whistles.

Visualforce also opens the door to more programmatic control over your Flow.  You can create more complex data interactions, such as referencing static resources, by adding an Apex controller to a Visualforce page that calls a Flow.  You can also use a custom Apex controller to specify a variable finish location for the Flow, for example finishing on a newly created record detail page.

I have written about this previously on my blog, here: http://www.snugsfbay.com/2014/04/salesforce-flow-using-record-ids-at.html

You might also be interested in watching a Dreamforce session I co-presented on this topic, which includes all the code you need to customize your Flow from start to finish, including the unit test: http://dreamforce.vidyard.com/watch/7mBX_EQGTTz8pmZeo0724A

Either way, I hope that you'll agree Flow is a great tool for administrators who are interested in expanding their skills and taking on more complex business problems.  And it provides a great stepping stone into learning to code in Visualforce and Apex as well.