I have the following issue. Here is my target apex class that Ineed to test:
class TargetClass {
public static Id BatchId {get; set;}
public void methodOne() {
//adding an ApexAsyncJob in database and assign its ID ot BatchId
}
#Remote
public static String methodTwo(string batchId) {
//gets the ApexAsynJob inserted in previous method from database and //do some operations with it
}
}
And here is my testing class
#isTest
public TargetClassTest() {
static testmethod void test() {
test.startTest();
TargetClass tgtClass = new TargetClass();
tgtClass.methodOne();
TargetClass.methodTwo(TargetClass.BatchId);
}
}
When methodOne is done and methdTwo is called, we have the BatchId property assigned but the AsynApexJob is not in the database yet so methodtwo throws an exception. How can I solve it and finish my tests.
I have the following ideas
1. run methodTwo whenever the AsynApexJob is in the database. How can I do this? An endless loop checking the database doesn't work as we hit the limit of queries.
2. Mocking an AsyncApexJob. I dont necessarily need the AsynApexJob inserted in methodOne. Any would work. I don't know how to do it. When I tried to insert one in the database, I got an error message that INSERT insn't available in AsynApexJob.
It would be fine if someone can help me.
Thanks!
You can querying out the jobs, so after you schedule the job you can do this and then assert that the job was actually scheduled ..
List<AsyncApexJob> jobInfo = [SELECT Status,NumberOfErrors FROM AsyncApexJob];
System.assertEquals(jobInfo.size(), 1);
Related
I have inherited a mess of a code base and I have been asked to attempt to right effective "unit tests" and automated tests to support upcoming changes. We are using Crm 4.0. Here is an example of the code I am trying to Moq:
public static creditdebitcardEntity CreateCreditCardInstance(Transaction transaction, TransactionSet transactionSet, accountEntity stetyAccount)
{
try
{
//todo: check for existance
creditdebitcardEntity stetyCard;
ColumnSet customColumns = new ColumnSet();
customColumns.Attributes = new string[]{creditdebitcardEntity.creditdebitcardidName,
creditdebitcardEntity.expirationmonthName,
creditdebitcardEntity.expirationyearName,
creditdebitcardEntity.reasonheldName,
creditdebitcardEntity.heldonName,
creditdebitcardEntity.statuscodeName};
creditdebitcardEntity[] tempCard =
creditdebitcardDal.GetCreditCardEntityByHashcode(transaction.CreditCards.CreditCardHash, customColumns);
if (tempCard != null)
return tempcard;
else
return null;
}
catch (Exception ex)
{
DirectiveExceptions.ReturnStagingException("CreditCardDirectives", "CreateCreditCardInstance", "An error occurred when trying to create a credit card transaction instance for folio " + transaction.SourceTransactionID + ". Contact a system administrator", ex, transaction.SourceTransactionKey);
return null;
}
}
so my question is this; how do I mock out the call to the CreditDebitCardDal? I cannot make changes to the code base without having to go through a bunch of wickets. I can introduce new code with little effort, but modifying the existing code requires a lot of regression testing.
I do understand how to mock out the call to the static method and passing in the required objects is no issue at all either. I just don't want to rely on my SUT having a Crm database to ensure that the code is working. I am thinking that I could create an Interface to the Dal Class and then mock that interface, but wanted to see if there was a better way before I started down that road.
Thanks and let me know if I can provide any additional details.
Chuck
I would mock out the parameters to start with. Extract an interface from Transaction, TransactionSet, accountEntity. From this you can then mock out the dependencies. You will have some more work to do but should be along the lines of below. The code below is just to show you, it is not tested or compiled
[TestFixture]
public class CreditDebitCardUnitTests
{
private Mock<ITranscation> MockTransaction {get ; set;}
private Mock<ITransactionSet> MockTransactionSet {get; set;}
private Mock<IAccountEntity> MockAccountEntity {get; set;}
[Setup]
public void TestFixtureSetup()
{
MockTransaction = new Mock<ITransaction>();
MockTransactionSet = new Mock<ITransactionSet>();
MockAccountEntity = new Mock<IAccountEntity>();
}
[Test]
[Category("CreditCard tets")]
public void VerfiyCreditDebitCardDal_GetCreditCardEntityByHashcode_Gets_Called
{
//Arrange
ColumnSet customColumns = new ColumnSet();
customColumns.Attributes = new string[]{creditdebitcardEntity.creditdebitcardidName,
creditdebitcardEntity.expirationmonthName,
creditdebitcardEntity.expirationyearName,
creditdebitcardEntity.reasonheldName,
creditdebitcardEntity.heldonName,
creditdebitcardEntity.statuscodeName};
MockTransaction.Setup(x => x.CreditCards.CreditCardHash).Returns(It.IsAny<Hash>)
//Act
creditdebitcardEntity[] tempCard =
creditdebitcardDal.GetCreditCardEntityByHashcode(MockTransaction.ObjectCreditCards.CreditCardHash, customColumns )
//Assert
}
}
I am using NSubstitute for my Unit tests. I need to check that a object is send to a void method inside the method I am testing. I only need to check that the object is sent with one of the properties being a certain value.
eg.
///The object in question
public class Person
{
public string Name { get; set; }
public string Surname{get;set;}
}
Two simple methods
public void NameStartsWithA(Person person)
{
//do something to person when name starts with A
}
public void NameStartsWithB(Person person)
{
//do something to person when name starts with B
}
The method i am writing the test for.
public void MethodBeingTested()
{
var person = new Person() {Name = "Adrian",Surname="SomeSurname"};
if(person.Name.StartsWith("A"))
NameStartsWithA(person);
else
NameStartsWithB(person);
}
If the person name starts with an A, I need to check, using NSubstitute that the "NameStartsWithA" was called with a name that starts with an A.
My Unit Test so far looks something like this
_someService.Received().NameStartsWithA(new Person(){Name="Adrian",Surname=Arg.Any<string>()});
But Nsubstitute says the function was never called, but when I do the same test with "RecievedArgumentsAny()" then it passes.
Hope this example helps you in understanding what I am trying to accomplish.
got this to work. Posting the code.
_someService.Received().NameStartsWith(Arg.Is<Person>(p => p.Name.Startswith== "A"));
hopes this will help someone in the future.
When unit testing with RavenDb, it is often the case that newly added data is retrieved or otherwise processed. This can lead to 'stale index' exceptions e.g.
Bulk operation cancelled because the index is stale and allowStale is false
According to a number of answers
How should stale indexes be handled during testing?
WaitForNonStaleResults per DocumentStore
RavenDb : Update a Denormalized Reference property value
The way to force the database (the IDocumentStore instance) to wait until its indexes are not stale before processing a query or batch operation is to use DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites during the IDocumentStore initialisation, like this:
public class InMemoryRavenSessionProvider : IRavenSessionProvider
{
private static IDocumentStore documentStore;
public static IDocumentStore DocumentStore
{
get { return (documentStore ?? (documentStore = CreateDocumentStore())); }
}
private static IDocumentStore CreateDocumentStore()
{
var store = new EmbeddableDocumentStore
{
RunInMemory = true,
Conventions = new DocumentConvention
{
DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites,
IdentityPartsSeparator = "-"
}
};
store.Initialize();
IndexCreation.CreateIndexes(typeof (RavenIndexes).Assembly, store);
return store;
}
public IDocumentSession GetSession()
{
return DocumentStore.OpenSession();
}
}
Unfortunately, the code above does not work. I am still receiving exceptions regarding stale indexes. These can be resolved by putting in dummy queries that include .Customize(x => x.WaitForNonStaleResultsAsOfLastWrite()).
This is fine, as long as these can be contained in the Unit Test, but what if they can't? I am finding that these WaitForNonStaleResults* calls are creeping into production code just so I can get unit-tests to pass.
So, is there a sure fire way, using the latest version of RavenDb, to force the indexes to freshen before allowing commands to be processed - for the purposes of unit testing only?
Edit 1
Here is a solution based on the answer give below that forces a wait until the index is not stale. I have written it as an extension method for the sake of unit-testing convenience;
public static class IDocumentSessionExt
{
public static void ClearStaleIndexes(this IDocumentSession db)
{
while (db.Advanced.DatabaseCommands.GetStatistics().StaleIndexes.Length != 0)
{
Thread.Sleep(10);
}
}
}
And here is a Unit Test that was using the verbose WaitForNonStaleResultsAsOfLastWrite technique but now uses the neater extension method.
[Fact]
public void Should_return_list_of_Relationships_for_given_mentor()
{
using (var db = Fake.Db())
{
var mentorId = Fake.Mentor(db).Id;
Fake.Relationship(db, mentorId, Fake.Mentee(db).Id);
Fake.Relationship(db, mentorId, Fake.Mentee(db).Id);
Fake.Relationship(db, Fake.Mentor(db).Id, Fake.Mentee(db).Id);
//db.Query<Relationship>()
// .Customize(x => x.WaitForNonStaleResultsAsOfLastWrite())
// .Count()
// .ShouldBe(3);
db.ClearStaleIndexes();
db.Query<Relationship>().Count().ShouldBe(3);
MentorService.GetRelationships(db, mentorId).Count.ShouldBe(2);
}
}
If you have a Map/Reduce index, DefaultQueryingConsistency = ConsistencyOptions.QueryYourWrites won't work. You need to use an alternative method.
In your units tests, call code like this, straight after you've inserted any data, this will force the all indexes to update before you do anything else:
while (documentStore.DatabaseCommands.GetStatistics().StaleIndexes.Length != 0)
{
Thread.Sleep(10);
}
Update You can of course put it in an extension method if you want to:
public static class IDocumentSessionExt
{
public static void ClearStaleIndexes(this IDocumentSession db)
{
while (db.Advanced.DatabaseCommands.GetStatistics().StaleIndexes.Length != 0)
{
Thread.Sleep(10);
}
}
}
Then you can say:
db.ClearStaleIndexes();
You can actually add a query listener on the DocumentStore to wait for nonstale results. This can be used just for unit tests as it is on the document store and not each operation.
// Initialise the Store.
var documentStore = new EmbeddableDocumentStore
{
RunInMemory = true
};
documentStore.Initialize();
// Force queries to wait for indexes to catch up. Unit Testing only :P
documentStore.RegisterListener(new NoStaleQueriesListener());
....
#region Nested type: NoStaleQueriesListener
public class NoStaleQueriesListener : IDocumentQueryListener
{
#region Implementation of IDocumentQueryListener
public void BeforeQueryExecuted(IDocumentQueryCustomization queryCustomization)
{
queryCustomization.WaitForNonStaleResults();
}
#endregion
}
#endregion
(Shamelessly stolen from RavenDB how to flush?)
Be aware that StaleIndexes also include abondoned and disabled indices - which will never get up to date.
So to avoid waiting indefinetely use this property instead:
var staleIndices = store.DatabaseCommands.GetStatistics().CountOfStaleIndexesExcludingDisabledAndAbandoned;
I've got the following code and I need help to write a unit test for it. I'm using Moq library.
Here's the deal. I have a business class with a dependency to a repository (interface), so I can use it to save my entities to the database. My entity is basically a list of strings. The method AddAndSave, from MyBusinessClass, grab the value it receives as a parameters, put it into the list and call Save method from IRepository. Then, I clear the list of my entity. The code below show this example (I've made it simple so I can explain it here).
There's a unit test, too.
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace TestesGerais
{
public class MyEntity
{
public MyEntity()
{
MyList = new List<string>();
}
public List<string> MyList { get; set; }
}
public interface IRepository
{
void Save(MyEntity entity);
}
public class MyBusinessClass
{
public IRepository Repository { get; set; }
private MyEntity _entity = new MyEntity();
public void AddAndSave(string info)
{
_entity.MyList.Add(info);
Repository.Save(_entity);
_entity.MyList.Clear(); // for some reason I need to clear it
}
}
[TestClass]
public class UnitTest10
{
[TestMethod]
public void TestMethod1()
{
var mock = new Mock<IRepository>();
MyBusinessClass b = new MyBusinessClass() { Repository = mock.Object };
b.AddAndSave("xpto");
mock.Verify(m => m.Save(It.Is<MyEntity>(x => x.MyList[0] == "xpto")), Times.Exactly(1));
}
}
}
My unit-test check if the IRepository's Save method was called with its parameter (an entity) having one element in the list, and having the value "xpto" in this element.
When I run this test, it turns red with the error message "Test method TestesGerais.UnitTest10.TestMethod1 threw exception:
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index".
Ok, this is caused by the list that has been cleaned. If I comment the line "_entity.MyList.Clear();", everything goes well.
My question is: how can I test this without commenting the "Clear" line in my business class, and making sure that my repository's method is called passing the specific value (entity with one element with value "xpto")?
Thanks
I've changed my unit test using the Callback feature of Moq. This way, I can setup the mock so when AddAndSave is called, the parameter it receives is saved into a variable from my unit test, and I can assert it later.
[TestMethod]
public void TestMethod1()
{
var mock = new Mock<IRepository>();
string result = string.Empty;
mock.Setup(m => m.Save(It.IsAny<MyEntity>())).Callback((MyEntity e) => { result = e.MyList[0]; });
MyBusinessClass b = new MyBusinessClass() { Repository = mock.Object };
b.AddAndSave("xpto");
Assert.AreEqual(result, "xpto");
}
You could split your method up a bit. "AddAndSave" isn't all it does. You could then just test the behaviour of the adding and saving bit in isolation.
Using JPA2/Hibernate, I've created an entity A that has a uni-directional mapping to an entity X (see below). Inside A, I also have a transient member "t" that I am trying to calculate using a #PostLoad method. The calculation requires access to the assosiated Xs:
#Entity
public class A {
// ...
#Transient
int t;
#OneToMany(orphanRemoval = false, fetch = FetchType.EAGER)
private List listOfX;
#PostLoad
public void calculateT() {
t = 0;
for (X x : listOfX)
t = t + x.someMethod();
}
}
However, when I try to load this entity, I get a "org.hibernate.LazyInitializationException: illegal access to loading collection" error.
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:363)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
at org.hibernate.collection.PersistentBag.get(PersistentBag.java:445)
at java.util.Collections$UnmodifiableList.get(Collections.java:1154)
at mypackage.A.calculateT(A.java:32)
Looking at hibernate's code (AbstractPersistentCollection.java) while debugging, I found that:
1) My #PostLoad method is called BEFORE the "listOfX" member is initialized
2) Hibernate's code has an explicit check to prevent initialization of an eagerly fetched collection during a #PostLoad:
protected final void initialize(boolean writing) {
if (!initialized) {
if (initializing) {
throw new LazyInitializationException("illegal access to loading collection");
}
throwLazyInitializationExceptionIfNotConnected();
session.initializeCollection(this, writing);
}
}
The only way I'm thinking to fix this is to stop using #PostLoad and move the initialization code into the getT() accessor, adding a synchronized block. However, I want to avoid that.
So, is there a way to have eager fetching executed prior to #PostLoad being called? I don't know of a JPA facility to do that, so I'm hoping there's something I don't know.
Also, perhaps Hibernate's proprietary API has something to control this behaviour?
This might be too late, but hibernate seems not to support the default jpa fetchtype option
#OneToMany(orphanRemoval = false, fetch = FetchType.EAGER)
You must use the hibernate specific one:
#LazyCollection(LazyCollectionOption.FALSE)
I don't know how to fix this but I think a little refactoring might help, the idea would be to move the code to a #PostConstruct
so for example your class would be:
#Entity
public class A {
// ...
#Transient
int t;
#OneToMany(orphanRemoval = false, fetch = FetchType.EAGER)
private List listOfX;
#PostConstruct
public void calculateT() {
t = 0;
for (X x : listOfX)
t = t + x.someMethod();
}
}
The server will call PostConstruct as soon as it has completed initializing all the container services for the bean.
Updated link to bug report:
https://hibernate.atlassian.net/browse/HHH-6043
This is fixed in 4.1.8 and 4.3.0 or later