How do you properly test for loop queries within test classes? - unit-testing

I have a Schedulable class which will get called once per night. I have run the code anonymously and everything works as it should. The problem I am having is that I cannot get proper test coverage on it! I have written a test class that I believe should work, but for some reason any lines within my for-loops are not being covered.
I assume that it is because no data is being returned from these queries, however there are thousands of records that should be returned. I have run the queries on the production environment without any issues.
Is there a separate process for running queries in a schedulable class?
Here's part of my class:
global class UpdateUnitPrice implements Schedulable{
global void execute(SchedulableContext sc){
// OwnerId -> List of Strings with Row Contents
Map<Id,Map<Id,Map<String,String>>> updateContainer = new Map<Id,Map<Id,Map<String,String>>>{}; // Covered
List<Id> ownerContainer = new List<Id>{}; // Covered
String EmailMessage; // Covered
String EmailLine; // Covered
String EmailAddedLines; // Covered
String CurrentEmailLine; // Covered
String NewEmailLine; // Covered
List<Id> opportunityList = new List<Id>{}; // Covered
for(Opportunity thisOpp :[SELECT Id,Name FROM Opportunity WHERE Order_Proposed__c = null])
{
// Thousands of records should be returned
opportunityList.add(thisOpp.Id); // NOT COVERED!!
}
List<OpportunityLineItem> OppLineItemList = new List<OpportunityLineItem>{}; // Covered
for(OpportunityLineItem thisOppProd : [SELECT Id,OpportunityId,Opportunity.OwnerId,Opportunity.Name,Product_Name__c,UnitPrice,ListPrice
FROM OpportunityLineItem
WHERE OpportunityId IN :opportunityList
AND UnitPrice_lt_ListPrice__c = 'True'
ORDER BY OpportunityId ASC])
{
. . . // NO LINES COVERED WITHIN THIS LOOP
}
. . .
}
}
Here's my test class:
#isTest
private class UpdateUnitPriceTest {
static testMethod void myUnitTest() {
Test.startTest();
// Schedule the test job
String jobId = System.schedule('UpdateUnitPrice','0 0 0 3 9 ? 2022',new UpdateUnitPrice());
// Get the information from the CronTrigger API object
CronTrigger ct = [SELECT Id, CronExpression, TimesTriggered, NextFireTime FROM CronTrigger WHERE id = :jobId];
// Verify the expressions are the same
System.assertEquals(ct.CronExpression,'0 0 0 3 9 ? 2022');
// Verify the job has not run
System.assertEquals(0, ct.TimesTriggered);
// Verify the next time the job will run
System.assertEquals('2022-09-03 00:00:00', String.valueOf(ct.NextFireTime));
Test.stopTest();
}
}
Am I supposed to specifically reference something within these for-loops for them to fire? This Class should be able to just run everything on it's own without inserting records for testing. What am I missing?
Thanks in advance for any help given!

There was a lovely feature added to API 24.0 which requires test classes to include a small (new) line of code in order to view queried data. I have no idea why this was implemented, but it sure did trip me up.
For our test classes to run properly, they now must have the following at the top:
#isTest (SeeAllData = true)
Previously, all that was needed was:
#isTest
You can read more on test classes and this new "feature" here: Apex Test Class Annotations

Related

Reset id sequence or update id on Grails Test

In Grails 1.3.7, I have a code that filters objects by ID and I need to test that
The domain class has a sequence
static mapping = {
id generator: 'sequence', params[sequence: 'seq_shipping_service']
}
In the test, the object is created several times and I need the identifier to be 11 in all the tests and even though, it deletes the whole database between every test, it doesn't reset the sequence. So I would get a superior ID
foo = createFoo()
foo.id = 11l
foo.save () //This gets error
My ideas are
1) Reset somehow the id sequence so it's everytime the same number between tests
2) Set somehow the id
I don't know if I make myself clear
Personally, if I need to do something like this I:
create an object mother to spawn all required objects (i.e. foo.id == 11)
use Groovy SQL to insert data into database. In your case:
public class BlahBlahTest extends Specification {
DataSource dataSource
def setup () {
new Sql(dataSource).exec ("insert into blablah (11, ...)")
}
...
Obviously you could do anything else there - for example recreate the sequence to start with 11.

How do I assert activity counts in a workflow trace after a unit test?

I am unit testing a WF4 service using the Unit testing Nuget package. There is a functionality for asserting that stuff does or does not exist in the end-of-test tracking information.
Consider the following unit test code:
WorkflowServiceTestHost host = null;
using (host = CreateHost())
{
var proxy = new ServiceClient(Binding, ServiceAddress);
// Call receive points in the workflow
}
finally
{
host.Tracking.Trace();
// I would like to assert stuff like the WF did not abort
// For now, I would just like to assert that there are a
// certain number of invocations of a specific activity.
// I can find no examples of how to call this:
host.Tracking.Assert.ExistsCount(?????what goes here???);
}
How does one call ExistsCount()? The prototype looks like this:
public void ExistsCount<TRecord>(Predicate<TRecord> predicate, int count, string message = null) where TRecord : TrackingRecord
but I can find no examples or documentation to understand what is expected for the predicate.
Well, it turns out that the easiest way to handle this is not via
host.Tracking.Assert.ExistsCount()
rather you want to look at the collection
host.Tracking.Records
and then use LINQ on them to confirm what you think should be there. For instance if you expected the workflow to call the ABC activity class five times you could check it as follows:
var trackingRecords = host.Tracking.Records.ToArray();
var myRecords = trackingRecords.OfType<ActivityStateRecord>()
.Where(
r =>
r.Activity != null && r.State == "Executing" &&
r.Activity.TypeName.EndsWith("ABC")).ToArray();
Assert.AreEqual(5,myRecords.Length);

Issue when mocking Logger

I am having a strange issue when mocking the log field of a class. Running the same test twice shows an error the second time. This is an example of code:
class AccountConfigJSON {
static Logger log = Logger.getLogger(AccountConfigJSON.class)
def AccountConfigJSON(String jsonString) {
if (jsonString) {
json = new JSONObject(jsonString)
} else {
log.debug("No JSON string for account config. Will not parse")
}
}
}
and this is the specification
class AccountConfigJSONUnitSpec extends UnitSpec {
def loggerMock
def setup(){
loggerMock = Mock(org.apache.log4j.Logger)
org.apache.log4j.Logger.metaClass.static.getLogger = { Class clazz -> loggerMock }
}
def 'If jsonString is null, a log is written'(){
when:
new AccountConfigJSON("")
then:
1 * loggerMock.debug("No JSON string for account config. Will not parse")
}
def 'If jsonString is empty, a log is written'(){
when:
new AccountConfigJSON("")
then:
1 * loggerMock.debug("No JSON string for account config. Will not parse")
}
}
The second test fails showing
| Too few invocations for:
1 * loggerMock.debug("No JSON string for account config. Will not parse") (0 invocations)
but debugging the app using Idea, clearly it runs this sentence. Any idea?
Looks odd that the actual call is executed but the interaction in not recorded. You can get around with it by explicitly assigning the mocked logger to the class as below:
def setup(){
loggerMock = Mock(org.apache.log4j.Logger)
AccountConfigJSON.log = loggerMock
}
From the definition of "interaction", I think the above setup is the best way to go.
Is an Interaction Just a Regular Method Invocation?
Not quite. While an interaction looks similar to a regular method
invocation, it is simply a way to express which method invocations are
expected to occur. A good way to think of an interaction is as a
regular expression that all incoming invocations on mock objects are
matched against. Depending on the circumstances, the interaction may
match zero, one, or multiple invocations.
This only happens while dealing with static object properties in a class. The moment logger is defined non-static in the class under test, everything works as expected without the work around.

Grails unit tests not recognizing .save() on a domain class

I am trying to be a good little programmer and set up Unit tests for my Grails 2.2.3 app. The unit tests that use GORM's injected .save() method are apparently not persisting to the mock test DB. For an example, here is what one test consists of:
#TestFor(TermService)
#Mock(Term)
class TermServiceTests {
void testTermCount() {
def t = new Term(code: "201310").save(validate: false, flush: true, failOnError: true)
println "Printing Term: " + t.toString()
assert 1 == Term.count() // FAILS
assert service.isMainTerm(t) // FAILS
}
}
I did a println that ends up printing Printing Term: null, meaning the Term did not save and return a Term instance. The first assertion is false with Term.count() returning 0.
Does anyone know why this might be? I have a mock Term and TermService (via the TestFor annotation, I believe), so I'm not quite sure why this wouldn't work. Thanks!
Edit: Here is my Term class.
class Term {
Integer id
String code
String description
Date startDate
Date endDate
static mapping = {
// Legacy database mapping
}
static constraints = {
id blank: false
code maxSize: 6
description maxSize: 30
startDate()
endDate()
}
}
Looks like id generator is assigned since you have mentioned about using legacy database. Plus id is not bindable by default in domain class (map construct won't work for id). So, I think you have to end up using like below:
def t = new Term(code: "201310")
t.id = 1
t.save(...)

EF Code First issue on CommitTransaction - using Repository pattern

I am having an issue with EF 4.1 using "Code First". Let me setup my situation before I start posting any code. I have my DBContext class, called MemberSalesContext, in a class library project called Data.EF. I have my POCOs in a seperate class library project called Domain. My Domain project knows nothing of Entity Framework, no references, no nothing. My Data.EF project has a reference to the Domain project so that my DB context class can wire up everything in my mapping classes located in Data.EF.Mapping. I am doing all of the mappings in this namespace using the EntityTypeConfiguration class from EntityFramework. All of this is pretty standard stuff. On top of Entity Framework, I am using the Repository pattern and the Specification pattern.
My SQL Server database table has a composite primary key defined. The three columns that are part of the key are Batch_ID, RecDate, and Supplier_Date. This table as an identity column (database generated value => +1) called XREF_ID, which is not part of the PK.
My mapping class, located in Data.EF.Mapping looks like the following:
public class CrossReferenceMapping : EntityTypeConfiguration<CrossReference>
{
public CrossReferenceMapping()
{
HasKey(cpk => cpk.Batch_ID);
HasKey(cpk => cpk.RecDate);
HasKey(cpk => cpk.Supplier_Date);
Property(p => p.XREF_ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
ToTable("wPRSBatchXREF");
}
}
My MemberSalesContext class (inherits from DBContext) looks like the following:
public class MemberSalesContext : DbContext, IDbContext
{
//...more DbSets here...
public DbSet<CrossReference> CrossReferences { get; set; }
//...more DbSets here...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
//...more modelBuilder here...
modelBuilder.Configurations.Add<CrossReference>(new CrossReferenceMapping());
//...more modelBuilder here...
}
}
I have a private method in a class that uses my repository to return a list of objects that get iterated over. The list I am referring to is the outermost foreach loop in the example below.
private void CloseAllReports()
{
//* get list of completed reports and close each one (populate batches)
foreach (SalesReport salesReport in GetCompletedSalesReports())
{
try
{
//* aggregate sales and revenue by each distinct supplier_date in this report
var aggregates = BatchSalesRevenue(salesReport);
//* ensure that the entire SalesReport breaks out into Batches; success or failure per SalesReport
_repository.UnitOfWork.BeginTransaction();
//* each salesReport here will result in one-to-many batches
foreach (AggregateBySupplierDate aggregate in aggregates)
{
//* get the batch range (type) from the repository
BatchType batchType = _repository.Single<BatchType>(new BatchTypeSpecification(salesReport.Batch_Type));
//* get xref from repository, *if available*
//* some will have already populated the XREF
CrossReference crossReference = _repository.Single<CrossReference>(new CrossReferenceSpecification(salesReport.Batch_ID, salesReport.RecDate, aggregate.SupplierDate));
//* create a new batch
PRSBatch batch = new PRSBatch(salesReport,
aggregate.SupplierDate,
BatchTypeCode(batchType.Description),
BatchControlNumber(batchType.Description, salesReport.RecDate, BatchTypeCode(batchType.Description)),
salesReport.Zero_Sales_Flag == false ? aggregate.SalesAmount : 1,
salesReport.Zero_Sales_Flag == false ? aggregate.RevenueAmount : 0);
//* populate CrossReference property; this will either be a crossReference object, or null
batch.CrossReference = crossReference;
//* close the batch
//* see PRSBatch partial class for business rule implementations
batch.Close();
//* check XREF to see if it needs to be added to the repository
if (crossReference == null)
{
//*add the Xref to the repository
_repository.Add<CrossReference>(batch.CrossReference);
}
//* add batch to the repository
_repository.Add<PRSBatch>(batch);
}
_repository.UnitOfWork.CommitTransaction();
}
catch (Exception ex)
{
//* log the error
_logger.Log(User, ex.Message.ToString().Trim(), ex.Source.ToString().Trim(), ex.StackTrace.ToString().Trim());
//* move on to the next completed salesReport
}
}
}
All goes well on the first iteration of the outer loop. On the second iteration of the outer loop, the code fails at _repository.UnitOfWork.CommitTransaction(). The error message returned is the following:
"The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges."
In this situation, the database changes on the second iteration were not committed successfully, but the changes in the first iteration were. I have ensured that objects in the outer and inner loops are all unique, adhering to the database primary keys.
Is there something that I am missing here? I am willing to augment my code samples, if it proves helpful. I have done everything within my capabilities to troubleshoot this issue, minus modifying the composite primary key set on the database table.
Can anyone help??? Much thanks in advance! BTW, sorry for the long post!
I am answering my own question here...
My issue had to do with how the composite primary key was being defined in my mapping class. When defining a composite primary key using EF Code First, you must define it like so:
HasKey(cpk => new { cpk.COMPANYID, cpk.RecDate, cpk.BATTYPCD, cpk.BATCTLNO });
As opposed to how I had it defined previously:
HasKey(cpk => cpk.COMPANYID);
HasKey(cpk => cpk.RecDate);
HasKey(cpk => cpk.BATTYPCD);
HasKey(cpk => cpk.BATCTLNO);
The error I was receiving was that the ObjectContext contained multiple elements of the same type that were not unique. This became an issue in my UnitOfWork on CommitTransaction. This is because when the mapping class was instanciated from my DBContext class, it executed 4 HasKey statements shown above, with only the last one for property BATCTLNO becoming the primary key (not composite). Defining them inline, as in my first code sample above, resolves the issue.
Hope this helps someone!