Difference between pages "FitnesseSlim" and "File:GMFigura24.jpg"

From ADempiere
(Difference between pages)
Jump to: navigation, search
This Wiki is read-only for reference purposes to avoid broken links.
m (Wikipage Troubleshooting)
 
 
Line 1: Line 1:
{{Note|I am using [http://fitnesse.org/FitNesse.UserGuide.SliM Fitnesse Slim] to upgrade [[TestFramework]]. Expect more updates from time to time. Participants are welcome. - [[User:Red1|Redhuan D. Oon]]}}
 
  
[[Image:FitnesseLoginPage.gif|thumb|440px|right|Wiki page with data to trigger setters and methods in ADempiereLogin.java - POC upgraded with Slim version of Fitnesse]]
 
=Background=
 
*This page follows and stands on the good work from [[TestFramework]] based on [[Fitnesse]].
 
*Here i recall how i researched to do a [[Cost Engine/Testing]] framework.
 
*The sourcecode for testing the following including the wiki page is online at:
 
**http://adempiere.svn.sourceforge.net/viewvc/adempiere/FitnesseSlim/
 
**Place the code anywhere in your ADempiere server and compile its bin for the !path statement later.
 
*Once you downloaded [http://www.fitnesse.org FitnesseSlim] (which is just the latest Fitnesse without any upgrading) and launch it via
 
java -jar fitnesse.jar -p 8080
 
*.. you are ready to go!
 
 
=WikiText=
 
[[Image:FitnesseExcel.gif|thumb|right|450px|You can also convert the test to Excel format and vice versa]]
 
*From the Frontpage at your
 
http://localhost:8080/
 
*You can edit the FrontPage and create a sub-page i.e.
 
>LoginPage
 
*This will then lead to a new page for you to edit. You can put in following text (edit the !paths to your local server occurrences):
 
<pre>
 
!define TEST_SYSTEM {slim}
 
!path /Users/red1/Documents/workspace/FitnesseSlim/bin
 
!path /Users/red1/Documents/projects/Fitnesse/fitnesse.jar
 
!path /Applications/Adempiere/lib/Adempiere.jar
 
!path /Applications/Adempiere/lib/AdempiereCLib.jar
 
 
|import|
 
|fit|
 
 
!|ADempiere Login                                |
 
|User    |Password|Client|ClientID?|Role|execute?|
 
|SuperUser|System  |System|$p=      |0  |true    |
 
|SuperUser|System|GardenWorld|$p=      |102 |true    |
 
|GardenAdmin|GardenAdmin|GardenWorld|$p=      |0 |true    |
 
|GardenAdmin|GardenAdmin|GardenWorld|$p=      |102 |true    |
 
|SuperUser|System|GardenWorld|$p=      |0 |true    |
 
</pre>
 
*On saving the page should look as shown at the top.
 
 
=POC for ADempiereLogin=
 
[[Image:FitnesseSlimLoginSuccess.gif|thumb|440px|right|Purposely made wrong asserts to prove that the Test Engine really works.]]
 
[[Image:FitnesseAsserts.gif|thumb|440px|right|A successful POC Login with easy user data to test true/false conditions. Just hit the ''Test'' button and get it intuitively on the same/single page.]]
 
*I reused CarlosRuiz's code and refactored them:
 
**''r14692 /FitnesseSlim/src/fit/ (ADempiereLogin.java ModelLogin.java)'': Refactored ADempiereLogin as Fitnesse '''Fixture should not contain logic code''' but just Fixture data
 
**''r14693 /FitnesseSlim/src/fit/ (ADempiereLogin.java ModelLogin.java)'': '''Fixture should not produce output''', just true/false or assert types for Fitnesse final result.
 
**''r14694 /FitnesseSlim/src/fit/ADempiereLogin.java'': Fixture parse wiki input to be free from needing to put in @Ref tags, as '''column corresponds directly to Setter''' in java.
 
*Tests are easily setup and the results are easily read:
 
 
=Developer Notes=
 
==WikiPage Format==
 
*Wiki pages for Fitnesse are called StoryTests. They can comprise of Import, Path, Table or arrange in a Suite.
 
*The title label at the top of the table is used to look for the java class in your path bin.
 
**i.e. ''ADempiere Login'' will look for '''ADempiereLogin.class'''. The words are automatically joined.
 
*Fitnesse can work as a '''Suite''' where multiple classes with respective tables point to a single ''Suite Page'', with '''Teardown''' at the end of it.
 
**Imports and Paths are then setup only once in the main suite page.
 
*The use of a simple multi-row decision table as above allows quick formulating of testing data and its handling in code.
 
*Each column title acts as either a property setter (''Client'') or a method (''ClientID?''). This is highly intuitive to a java coder.
 
*An ordinary label such as 'Client' will look for its '''setClient(String Client)''' method.
 
**As a setter allows me to obviously put any string parser at that setter method without asking again what that column type is.
 
**Each column will have its own setter method.
 
*To do something but not as a setter, then use a ''?''.
 
**By putting a question mark after a label, it will look for a method with the same word. I.e. 'ClientID?' will look for '''ClientID()''' method.
 
**It will post its ''return'' in the field space if a qualifier is present i.e. ''$P=''.
 
**This way we can return values from the test easily and quickly.
 
*As seen above, paths are put in the wikipage content to ensure the ADempiere jars are within its classpath during execution.
 
*I followed the geneJar.desc instruction from Sunny at [[TestFramework]], but I need not include ADempiereTrunk, as just making !path to ADHOME/lib/Adempiere.jar and ADHOME/lib/AdempiereCLib.jar is sufficient.
 
 
===StoryTest Troubleshooting===
 
*Ensure there are no spaces at the end of the whole line. I mean after the last '|'.
 
*Ensure that the setter column is filled in with values. If a value is not used, just put in zero - 0.
 
*Do not have double spacings in between columns. Sometimes it breaks the format.
 
*You can easily check if formating is ok by just pressing 'save' of the edit and view if the table comes out completely.
 
 
==SourceCode==
 
*A big thanks to CarlosRuiz for the bulk of the gruntwork in making a proper testing code.
 
*The tests were trying to see which login info goes with which Role ID.
 
*Upon testing and debugging, i noted in my refactored code that the ADempiereInstance happens only once. This saves time for repeating rows to test.
 
**I ensured this by refactoring it into a superclass constructor:
 
<pre>
 
public ModelLogin() {
 
if (adempiereInstance == null) {
 
adempiereInstance = StaticAdempiereInstance.getInstance();
 
}
 
}
 
</pre>
 
*Furthermore the code (done by Carlos) already checks for different login info before relogin again.
 
<pre>
 
//Share login between different sessions
 
if (  m_ads != null
 
&& m_ads.isLoggedIn()
 
&& m_ads.getM_AD_Client_ID() == m_client_id
 
&& m_ads.getM_AD_Org_ID() == m_org_id
 
&& m_ads.getAD_Role_ID() == m_role_id
 
&& m_ads.getM_Warehouse_ID() == m_warehouse_id
 
&& m_ads.getUser().equals(m_user)
 
)
 
return true; // already logged with same data
 
</pre>
 
 
==Look Up Case==
 
[[Image:FitnesseLookUpCase.gif|thumb|left|400px|Versatility of Fitnesse to get objects with simple coding]]
 
*Here we try to prove how versatile Fitnesse is.
 
*It can traverse few objects on the same page. I.e. it can pass a variable return from one object as an argument of the other. See the appearances of '$I' below. It turns out to be '114' in the test run.
 
*The example here extends the same text and 2 very simple extra classes.
 
*The Fitnesse wiki text:
 
<pre>
 
|import|
 
|fit|
 
 
!|ADempiere Login                                |
 
|User    |Password|Client|ClientID?|Role|execute?|
 
|GardenAdmin|GardenAdmin|GardenWorld|      |102 |true    |
 
 
!|Look up Order    |
 
|Record ID | Business Partner Name? | BPartner ID? |
 
|1000009 || $I= |
 
 
!|Get Details of | $I |
 
|Name of Country?| 
 
|  |
 
</pre>
 
*The 2 extra classes:
 
<pre>
 
package fit;
 
 
import org.compiere.util.Env;
 
import org.compiere.model.*;
 
 
public class LookUpOrder {
 
private int RecordID;
 
MOrder order = null;
 
 
public void setRecordID(int recID) {
 
this.RecordID = recID;
 
}
 
 
public String BusinessPartnerName(){
 
order = new MOrder(Env.getCtx(), RecordID, null);
 
return order.getC_BPartner().getName();
 
}
 
 
public int BPartnerID(){
 
return order.getC_BPartner_ID();
 
}
 
 
}
 
</pre>
 
<pre>
 
package fit;
 
 
import org.compiere.model.MBPartnerLocation;
 
import org.compiere.util.Env;
 
 
public class GetDetailsOf {
 
private int bpartnerid;
 
 
public GetDetailsOf(int partnerID) {
 
bpartnerid = partnerID;
 
}
 
 
public String NameOfCountry(){
 
MBPartnerLocation loc = new MBPartnerLocation(Env.getCtx(), bpartnerid, null);
 
return loc.getLocation(true).getCountryName();
 
}
 
}
 
</pre>
 
 
*Please look up the SVN of http://sourceforge.net/projects/adempiere/ under /branches/FitnesseSlim for the example code here. [http://adempiere.svn.sourceforge.net/viewvc/adempiere/branches/FitnesseSlim/ Browse].
 
 
==Deploying==
 
*The classpath in the Fitnesse wiki page just points to:
 
ADEMPIERE_HOME/lib/Adempiere.jar
 
ADEMPIERE_HOME/lib/AdempiereCLib.jar
 
*If you have customization or patches jars, you need not put in the classpaths. Just RUN_silentsetup will incorporate them into the AdempiereCLib.jar
 
 
[[Category:Testing]]
 

Revision as of 04:28, 27 February 2009