Acumatica Unit Test
Hello readers of mine blog.
Today I want to share with everybody who wants to make unit test of Acumatica how I achieved it.
For unit testing I use NUnit. In order to start my work with Acumatica Unit testing I wrote the following class:
[TestFixture] public class CATranEntryExtTest { [Test] public void TestAutonumber() { var gr = PXGraph.CreateInstance<CATranEntry>(); } }
Now with help of Resharper let's start debugging:
And here we go, the first error message:
PX.Data.PXProviderException : Provider cannot be instantiated.
at PX.Data.PXDatabase.get_Provider() in c:\Builders\4_10-2013_12_16-23_17_15-Full\Scripts\BuildTemp\NetTools\PX.Data\Database\Provider.cs: line 388
at PX.Data.PXDatabase.GetSlot(String key, Type[] tables) in c:\Builders\4_10-2013_12_16-23_17_15-Full\Scripts\BuildTemp\NetTools\PX.Data\Database\Provider.cs: line 802
at PX.Data.PXGraph.a(Type A_0) in c:\Builders\4_10-2013_12_16-23_17_15-Full\Scripts\BuildTemp\NetTools\PX.Data\Graph\Graph.cs: line 2684
at PX.Data.PXGraph.CreateInstance(Type graphType) in c:\Builders\4_10-2013_12_16-23_17_15-Full\Scripts\BuildTemp\NetTools\PX.Data\Graph\Graph.cs: line 112
at PX.Data.PXGraph.CreateInstance() in c:\Builders\4_10-2013_12_16-23_17_15-Full\Scripts\BuildTemp\NetTools\PX.Data\Graph\Graph.cs: line 57
So, it means we need to add some connection string to the site. How to add it exactly? What proper way? I tried two next options:
1.
<?xml version="1.0" encoding="utf-8" ?> <configuration> <connectionStrings> <remove name="ProjectX" /> <add name="ProjectX" providerName="System.Data.SqlClient" connectionString="Data Source=DIO222\DIO195;Initial Catalog=Ac20140117;Integrated Security=False;User ID=sa;Password=1234" /> </connectionStrings> </configuration>
This way also:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <connectionString value="Data Source=DIO222\DIO195;Initial Catalog=Ac20140117;Integrated Security=False;User ID=sa;Password=1234"></connectionString> </configuration>
and if you suppose, that error message changed, you are wrong. It didn't go away.
Then I addressed support of Acumatica, and here is the answer:
you just need this config. That is not necessary to create and use real database. You just need connectionString specified.
In case if with answer you know how to add connectionString to app.config for unit test and it will work, let me congratulate you. For me you are genious. Sadly to admit, I'm not. After a while, I decided to do crazy idea - copy/paste web.config into App.config. Imagine scale of my surprise when I noticed, that error went away!!!!!!
Now I got the next error message:
PX.Data.PXNotLoggedInException : You are not currently logged in.
Do you have any idea how to log in?
In order to understand this idea lets go to Login.aspx.cs, maybe we can locate there something. For example method NormalLogin:
private void NormalLogin(string[] companies) { if (companies != null && companies.Length == 1) { cmbCompany.Items.Clear(); cmbCompany.Items.Add(companies[0]); } string loginText = txtUser.Text.Trim(); string userName = PXDatabase.Companies.Length > 0 ? loginText + "@" + (cmbCompany.SelectedIndex != -1 ? cmbCompany.SelectedItem.Value : PXDatabase.Companies[0]) : loginText; if (!PXLogin.LoginUser(ref userName, txtPass.Text)) { // we will change password during next round-trip PXContext.Session.SetString("ChangingPassword", txtPass.Text); DisablingUserPassword(); EnablingChangingPassword(); this.Master.Message = string.Empty; } else { PXLogin.InitUserEnvironment(userName, cmbLang.SelectedValue); } }
I'm considered about mehtod PXLogin.LoginUser. Lets use reflector in order to look there:
using (PXLoginScope pxLoginScope = new PXLoginScope(userName, new string[0]))using (PXLoginScope pxLoginScope = new PXLoginScope(userName, new string[0]))
I just think what can mean PXLoginScope. But maybe name is self-explanatory. Some scope where some login considered as working?
Lets write code similar to what reflector showed:
[Test] public void TestAutonumber() { using (var pxLoginScope = new PXLoginScope("someuserName", new string[0])) { var gr = PXGraph.CreateInstance<CATranEntry>(); } }
and now error message is
PX.Data.PXUndefinedCompanyException : Unable determine proper company id for the request.
At least we can see, that error message changes during our thinking process :).
All other conclusions were built on this code:
MembershipUser membershipUser = (MembershipUser) null; try { if (Membership.ValidateUser(pxLoginScope.UserName, password)) { membershipUser = Membership.GetUser(pxLoginScope.UserName); if (membershipUser != null) { pxLoginScope.UserName = membershipUser.UserName; userName = PXContext.PXIdentity.User.Identity.Name; if (pxLoginScope.CompanyName != null) { string[] rolesForUser = System.Web.Security.Roles.GetRolesForUser(pxLoginScope.UserName); if (rolesForUser == null || rolesForUser.Length == 0) throw new PXException("You are not allowed to login to the company {0}.", new object[1] { (object) pxLoginScope.CompanyName }); else if (!Enumerable.Contains<string>((IEnumerable<string>) PXDatabase.AvailableCompanies, pxLoginScope.CompanyName)) throw new PXException("You are not allowed to login to the company {0}.", new object[1] { (object) pxLoginScope.CompanyName }); } if (PXLogin.c(pxLoginScope.UserName)) return false; PXLogin.a(pxLoginScope.UserName, false); PXLogin.SetBranchID(pxLoginScope.UserName, pxLoginScope.CompanyName, pxLoginScope.Branch); PXSessionContextFactory.AuthenticateRequest(); PXLicenseHelper.OnAuthenticate(); return true; }
The function which has name a if to trust to reflector just updates some info in audit journal, and updates some info in db, which IMHO is not usable for unit test.
So, code, which I use now for initiating Unit test now looks like this:
[TestFixture] public class CATranEntryExtTest { [Test] public void TestAutonumber() { string userName = "some user name in db"; using (var pxLoginScope = new PXLoginScope(userName, new string[0])) { var membershipUser = (MembershipUser) null; // Membership.ValidateUser(pxLoginScope.UserName, "123"); membershipUser = Membership.GetUser(pxLoginScope.UserName); if (membershipUser != null) { pxLoginScope.UserName = membershipUser.UserName; userName = PXContext.PXIdentity.User.Identity.Name; if (pxLoginScope.CompanyName != null) { string[] rolesForUser = System.Web.Security.Roles.GetRolesForUser(pxLoginScope.UserName); if (rolesForUser == null || rolesForUser.Length == 0) throw new PXException("You are not allowed to login to the company {0}.", new object[1] { (object) pxLoginScope.CompanyName }); else if ( !Enumerable.Contains<string>((IEnumerable<string>) PXDatabase.AvailableCompanies, pxLoginScope.CompanyName)) throw new PXException("You are not allowed to login to the company {0}.", new object[1] { (object) pxLoginScope.CompanyName }); } PXLogin.SetBranchID(pxLoginScope.UserName, pxLoginScope.CompanyName, pxLoginScope.Branch); var gr = PXGraph.CreateInstance<CATranEntry>(); } } } }
At the end of execution gr looks like this:
Lets continue our way of unit testing for creating instance of our extension. This can be achieved via following way:
var accountsManager = gr.GetExtension<CATranEntryExt>();
Screenshot shows that we created instance of extension successfully:
Now I can test methods, which are inside of the extension CATranEntryExt.
I think it's enough for this article. If you have any comments, requests, wishes, critics, you are wormly welcome to express them.