When you are ready to record a script, make sure you are set up with the right starting state for your data and browser URL so you won't have to hop around or add/delete records at the beginning of your recording. Then simply record yourself executing your test. Segue does the rest at assembling your script based on all the network traffic you generate.
The first thing you want to do is build up a set of scripts that model the user load on your Flex application. Consider recording a few scripts you can combine in different ways to simulate real user load. For example, if your application requires a login, you might make several scripts:
Next add variability and loops to these scripts to simulate the natural variability you will see in your Flex application usage. For example, you may set the first script to log in, look up records a random number of times, and then log out. As you ramp up virtual users, each user will look up a different number of records before logging out, just as your real user population will. Of course, you have control over how to skew the randomness so that you can make it look like your real user population.
If your application does not have login and session management, you can actually structure your scripts in a different, simpler way:
Then you can have each virtual user chain together different, random patterns of logging in, then either looking up, adding, or printing, then logging out. Add to that the natural, random variability for the number of lookups, adds, and prints, and you have a very good real user simulation indeed.
For this article, I use the Restaurant Finder application by Christophe Coenraets. You can read about and download this application on his website. In this application, a typical user might select a region to list restaurants and then browse the list of restaurants. You will use that to model typical user behavior.
Any tool can record HTTP traffic and display a readable, editable script. Performance-testing tools have been supporting HTTP, XML, and web services for a long time and they will all work well for you if you use those protocols. When it comes to recording scripts against your Flex AMF application, however, you will begin to appreciate the extra integration that Segue has built into Silk Performer.
When you use AMF, communications between the client and server occur in a binary, compressed format. Recording AMF scripts without the integration built into Segue Silk Performer yields scripts full of binary hex codes. This is impossible to read and edit. For example, you could probably spot where the script was getting information from the server and correlate that to your actions but you would not be able to read the specific communications back and forth. This is a problem because you cannot verify that the script worked correctly when you play it back under load, and you cannot edit the script to provide the natural variability that you would anticipate in a real pool of users.
For example, if you record a test script against a Flex application using AMF without special integration, you will see something like this:
WebUrlPostBin("http://flexapps.macromedia.com/flex15/amfgateway",
"\h000000000001003373616D706C65732E" // •••••••3samples. 00000000
"\h72657374617572616E742E5265737461" // restaurant.Resta 00000010
"\h7572616E74536572766963652E676574" // urantService.get 00000020
"\h52657374617572616E747300022F3100" // Restaurants••/1• 00000030
"\h0000050A00000000", // •••••••• 00000040
STRING_COMPLETE, "application/x-amf");
WebUrlPostBin("http://flexapps.macromedia.com/flex15/amfgateway",
"\h000000000001003273616D706C65732E" // •••••••2samples. 00000000
"\h72657374617572616E742E5265737461" // restaurant.Resta 00000010
"\h7572616E74536572766963652E676574" // urantService.get 00000020
"\h52657374617572616E7400022F320000" // Restaurant••/2•• 00000030
"\h000E0A0000000100404A800000000000" // ••••••••@J•••••• 00000040
, STRING_COMPLETE, "application/x-amf");
WebUrl("http://flexapps.macromedia.com/flex15/restaurant/assets/pic/addis.jpg");
WebUrlEndPage(); // flex-internal
ThinkTime(46.5);
WebUrlPostBin("http://flexapps.macromedia.com/flex15/amfgateway",
"\h000000000001003273616D706C65732E" // •••••••2samples. 00000000
"\h72657374617572616E742E5265737461" // restaurant.Resta 00000010
"\h7572616E74536572766963652E676574" // urantService.get 00000020
"\h52657374617572616E7400022F330000" // Restaurant••/3•• 00000030
"\h000E0A0000000100404D000000000000" // ••••••••@M•••••• 00000040
, STRING_COMPLETE, "application/x-amf", 0.37);
WebUrl("http://flexapps.macromedia.com/flex15/restaurant/assets/pic/aquitaine.jpg", 10.16);
WebUrlPostBin("http://flexapps.macromedia.com/flex15/amfgateway",
"\h000000000001003273616D706C65732E" // •••••••2samples. 00000000
"\h72657374617572616E742E5265737461" // restaurant.Resta 00000010
"\h7572616E74536572766963652E676574" // urantService.get 00000020
"\h52657374617572616E7400022F340000" // Restaurant••/4•• 00000030
"\h000E0A0000000100404C000000000000" // ••••••••@L•••••• 00000040
, STRING_COMPLETE, "application/x-amf", 0.34);
WebUrl("http://flexapps.macromedia.com/flex15/restaurant/assets/pic/argana.jpg", 8.48);
WebUrlPostBin("http://flexapps.macromedia.com/flex15/amfgateway",
"\h000000000001003273616D706C65732E" // •••••••2samples. 00000000
"\h72657374617572616E742E5265737461" // restaurant.Resta 00000010
"\h7572616E74536572766963652E676574" // urantService.get 00000020
"\h52657374617572616E7400022F350000" // Restaurant••/5•• 00000030
"\h000E0A0000000100404F800000000000" // ••••••••@O•••••• 00000040
, STRING_COMPLETE, "application/x-amf", 0.36);
WebUrl("http://flexapps.macromedia.com/flex15/restaurant/assets/pic/aspasia.jpg", 9.46);
WebUrlPostBin("http://flexapps.macromedia.com/flex15/amfgateway",
"\h000000000001003273616D706C65732E" // •••••••2samples. 00000000
"\h72657374617572616E742E5265737461" // restaurant.Resta 00000010
"\h7572616E74536572766963652E676574" // urantService.get 00000020
"\h52657374617572616E7400022F360000" // Restaurant••/6•• 00000030
"\h000E0A0000000100404A000000000000" // ••••••••@J•••••• 00000040
, STRING_COMPLETE, "application/x-amf", 0.30);
WebUrl("http://flexapps.macromedia.com/flex15/restaurant/assets/pic/atasca.jpg");
By using Segue Silk Performer support for Flex AMF and recording the same script, however, you can see a readable, editable script that will serve you well:
WebPagePost("http://flexapps.macromedia.com/flex15/amfgateway", "<?xml version='1.0' encoding='UTF-8'?>\r\n"
"<SegueAmfXml version=\"0\">\r\n"
" <Msg length=\"5\"\r\n"
" operation=\"samples.restaurant.RestaurantService.getRestaurants\"\r\n"
" responseURI=\"/1\">\r\n"
" <StrictArray nrElems=\"0\"></StrictArray>\r\n"
" </Msg>\r\n"
"</SegueAmfXml>", STRING_COMPLETE, "application/x-amf", "getRestaurants");
WebPageAddUrl("restaurant/assets/pic/addis.jpg");
WebPagePost("http://flexapps.macromedia.com/flex15/amfgateway", "<?xml version='1.0' encoding='UTF-8'?>\r\n"
"<SegueAmfXml version=\"0\">\r\n"
" <Msg length=\"14\"\r\n"
" operation=\"samples.restaurant.RestaurantService.getRestaurant\"\r\n"
" responseURI=\"/2\">\r\n"
" <StrictArray nrElems=\"1\">\r\n"
" <Number>53</Number>\r\n"
" </StrictArray>\r\n"
" </Msg>\r\n"
"</SegueAmfXml>", STRING_COMPLETE, "application/x-amf", "getRestaurant");
WebPageAddUrl("restaurant/assets/pic/aquitaine.jpg");
ThinkTime(11.8);
WebPagePost("http://flexapps.macromedia.com/flex15/amfgateway", "<?xml version='1.0' encoding='UTF-8'?>\r\n"
"<SegueAmfXml version=\"0\">\r\n"
" <Msg length=\"14\"\r\n"
" operation=\"samples.restaurant.RestaurantService.getRestaurant\"\r\n"
" responseURI=\"/3\">\r\n"
" <StrictArray nrElems=\"1\">\r\n"
" <Number>58</Number>\r\n"
" </StrictArray>\r\n"
" </Msg>\r\n"
"</SegueAmfXml>", STRING_COMPLETE, "application/x-amf", "getRestaurant (#1)");
WebPageAddUrl("restaurant/assets/pic/argana.jpg");
ThinkTime(2.2);
WebPagePost("http://flexapps.macromedia.com/flex15/amfgateway", "<?xml version='1.0' encoding='UTF-8'?>\r\n"
"<SegueAmfXml version=\"0\">\r\n"
" <Msg length=\"14\"\r\n"
" operation=\"samples.restaurant.RestaurantService.getRestaurant\"\r\n"
" responseURI=\"/4\">\r\n"
" <StrictArray nrElems=\"1\">\r\n"
" <Number>56</Number>\r\n"
" </StrictArray>\r\n"
" </Msg>\r\n"
"</SegueAmfXml>", STRING_COMPLETE, "application/x-amf", "getRestaurant (#2)");
WebPageAddUrl("restaurant/assets/pic/aspasia.jpg");
ThinkTime(2.4);
WebPagePost("http://flexapps.macromedia.com/flex15/amfgateway", "<?xml version='1.0' encoding='UTF-8'?>\r\n"
"<SegueAmfXml version=\"0\">\r\n"
" <Msg length=\"14\"\r\n"
" operation=\"samples.restaurant.RestaurantService.getRestaurant\"\r\n"
" responseURI=\"/5\">\r\n"
" <StrictArray nrElems=\"1\">\r\n"
" <Number>63</Number>\r\n"
" </StrictArray>\r\n"
" </Msg>\r\n"
"</SegueAmfXml>", STRING_COMPLETE, "application/x-amf", "getRestaurant (#3)");
WebPageAddUrl("restaurant/assets/pic/atasca.jpg");
ThinkTime(2.5);
WebPagePost("http://flexapps.macromedia.com/flex15/amfgateway", "<?xml version='1.0' encoding='UTF-8'?>\r\n"
"<SegueAmfXml version=\"0\">\r\n"
" <Msg length=\"14\"\r\n"
" operation=\"samples.restaurant.RestaurantService.getRestaurant\"\r\n"
" responseURI=\"/6\">\r\n"
" <StrictArray nrElems=\"1\">\r\n"
" <Number>52</Number>\r\n"
" </StrictArray>\r\n"
" </Msg>\r\n"
"</SegueAmfXml>", STRING_COMPLETE, "application/x-amf", "getRestaurant (#4)");
Obviously, the Segue script created with built-in support for AMF is much more editable and usable.
When you record your script, it's helpful to plan the recording so you can execute it cleanly. Real users do not execute all scripts cleanly. However, you can provide natural variability in other ways, such as varying think times and playing scripts to add random noise. By recording clean scripts, you can edit the scripts more effectively and have more exact control over the load you are creating when you play back.
It's also helpful to add comments to your script while you are recording. You might add a comment, such as "Opening restaurant review" and "Restaurant review opened," to delineate clearly the request and response from the server. You also may want to use Silk Performer's transaction markers to indicate the beginning and end of a transaction so you can report on end-user transactions as a whole rather than as a series of client/server communications.