How to get active TGUITestRunner from DUnit test? - forms

TGUITestRunner form represents DUnit test results and created once by GUITestRunner.RunTest procedure:
procedure RunTest(test: ITest);
begin
with TGUITestRunner.Create(nil) do
begin
try
Suite := test;
ShowModal;
finally
Free;
end;
end;
end;
I want to extend it at runtime by writing colored status messages. It is possible, because that status messages at the bottom of GUI are placed into TRichEdit. So I need to get the pointer to this form somewhere in my TTestCase.
Can I do that without fixing the DUnit's code? Maybe you can recommend some hack?

A "decoupled" way to do it might be to use some "embedded codes" inside your status messages:
Status('<blue>Testing');
From within the dUnit test framework, you could check if the initial character of a status message is '<', and extract the arguments such as color or whatever else, and then modify dUnit to handle it.
That way, your tests will still run on an unmodified dUnit test runner. Several years from now you might want to move to the latest dUnit test, and I don't recommend making any API changes, or trying to access the test runner objects. The APIs and things you can see from within a test are strictly controlled on purpose. It's a principle of proper object oriented design, which the creators of jUnit/xUnit/dUnit believe in intensely.

Related

How to test Matlabs blocking uiconfirm?

I have a class with a simple user interface and want to write unit tests for all public member functions.
One of my buttons issues a warning via dialog. I use the uiconfirm function and assign the result to a variable to block the function until the user confirms the dialog.
classdef UI
properties
fig matlab.ui.Figure
button matlab.ui.control.Button
end
methods
function obj = UI()
obj.fig = uifigure();
obj.button = uibutton(obj.fig);
obj.button.Text = "click me";
obj.button.ButtonPushedFcn = #(~, ~) obj.click();
end
end
methods
function click(obj)
[~] = uiconfirm(obj.fig, "Something failed.", "Warning", ...
"Options", {'OK'}, "Icon", "warning");
end
end
end
I use class based unit tests:
https://de.mathworks.com/help/matlab/class-based-unit-tests.html
How can I test the click function?
I'm not quite sure if you're familiar with Matlab App Testing Framework. The App Testing Framework allows you to programmatically interact with appdesigner/uifigure apps. Take a look at the component-gesture availability matrix to help accelerate your UI Testing needs. Having said that, as of today, app testing framework doesn't yet support directly interacting with blocking UI Dialog's like uiconfirm.
An obvious brute force way of solving the blocking problem is to shadow the uiconfirm function in test with your custom version that could be non-blocking. If this is an easy enough acceptable solution for you, go forward with it. However, as your app changes and scales up, the mocks might need to get complicated too and thus become hard to maintain.
With that in mind, A better approach to test your app programmatically is to use a mocking framework to create a mock object to define the behavior of uiconfirm. The best way to achieve this is via Dependency Injection. In your case, the App could take/have a property that could store a context aware "UIConfirm [name it according to your workflow]" object . By default in a production environment, it would call the real uiconfirm command, but a “mock” or “stub” delegator could supply deterministic outputs to make the system more testable (and avoid the “blocking” dialog issue altogether) It’s certainly added overhead to do this in an otherwise simple App, but I get the sense that you value testing as much as we do!
Also please take a look at this detailed Mocking-App Testing example https://www.mathworks.com/help/matlab/matlab_prog/write-test-that-uses-app-testing-and-mocking-frameworks.html

Error message while using Test::MockObject->fake_module

I have inherited a perl project that I am having a problem testing. There are existing tests, and one of them uses the Test::MockObject->fake_module function. This test passes now. However, if I add a use (or use_ok) for an additional testing module (which also works ok in different tests), I am getting the following:
No mocked subs for loaded module 'IO::File'
In the test in question we have this:
my $io_file_mock = Test::MockObject->new();
$io_file_mock->set_isa('IO::File', 'IO::Handle');
$io_file_mock->set_true('flush', 'print');
$io_file_mock->fake_module('IO::File');
$io_file_mock->fake_new('IO::File');
I see in the documentation for MockObject->fake_module that this is written:
If you use fake_module() to mock a module that already exists in memory -- one you've loaded elsewhere perhaps, but do not pass any subroutines to mock, this method will throw an exception. This is because if you call the constructor later on, you probably won't get a mock object back and you'll be confused.
Not sure I understand this message and how I can make my test work.
Can anyone please help me?
Thanks
Solved in the comments:
I was able to solve my problem by putting the above code in a separate BEGIN block before the BEGIN block that calls my use_ok calls. Is there any problem with that? - Mark
A BEGIN code block is executed as soon as possible, that is, the moment it is completely defined, even before the rest of the containing file (or string) is parsed.
If the use_ok method that was failing is in a BEGIN block and it depended other variables, then those dependent variables would need to be initialized in a BEGIN block as well or they would be temporarily undef when use_ok was called.
For more information read: BEGIN, UNITCHECK, CHECK, INIT and END

Delphi Form Creation and Showing

I am trying to create an application with 2 forms in Delphi XE6. Depending on a ParamStr setting Form2 may or may not be shown before Form1.
In a quick test app both forms are created before Form1.Show is invoked - during which Form2 is shown or not
procedure TForm1.FormShow(Sender: TObject);
begin
if ParamStr(1) = 'foo' then
Form2.FooShow;
end;
procedure TForm2.FooShow;
begin
ShowModal;
end;
However in the "real" application I am seeing a different behaviour.
In this case Form1.Show is being called as soon as Application.CreateForm(TForm1, Form1) is called. This is before Form2 is being created, which is causing problems as Form2 doesn't exist when it is needed.
Any explanation why the behaviour would differ? Am I missing a setting buried somewhere in Project>Options
If your form is persisted with Visible set to True, then it will be shown as soon as it's created.
Setting the property to False should resolve your problem.
EDIT
PS: Just in case someone with a similar problem has their main form unexpectedly show even though Visible is set to False. This happens because by default the application will show the main form regardless of its Visible property in the call to Application.Run.
If so, the following question should help: How can I start Delphi application with the hidden main form?
EDIT2
For the sake of completeness, there are a couple other things that could cause a form to be shown as soon as it's created. However, these probably aren't applicable to this specific question.
Any code that explicitly shows the form when it's created (such as the OnCreate event) would obviously cause the form to be shown. However, one would hope that such actions don't lead to these kinds of questions.
An MDI child form can never be hidden. At best it can be minimised.
TIP
The quickest way to finding the answer to such questions is usually just a little bit of debugging.
Set a break-point in your FormShow method.
Go to Compiler Settings, and enable the option to build with debug DCU's. (You'll want to see the VCL code.)
Rebuild and run your application.
When you get to your break-point, open the Call Stack debug window.
Navigate the call-stack looking for the trigger.
In this case you should have found the following code in Forms.pas.
procedure TCustomForm.DoCreate;
begin
//...
if fsVisible in FFormState then Visible := True; //<-- The trigger
end;
And a little more investagation on fsVisible would reveal the root cause as: The Visible property is set to True.
That said, you don't want to be coding this way because you're creating dependencies via globals. This is error-prone; and your little experiment shows shows just one of many subtle things that can cause problems.
Rather avoid the globals with something like the following changes in your DPR:
begin
Application.Initialize;
ShowForms;
end;
Where ShowForms is implemented as:
procedure ShowForms;
var
LForm1: TForm1;
LForm2: TForm2;
begin
Application.CreateForm(TFrom1, LForm1);
Application.CreateForm(TFrom2, LForm2);
if (ParamStr(1) = 'foo') then
LForm2.Show
else
LForm1.Show;
end;
If you don't have any dependencies between the forms, the above will suffice.
If you do have a dependency, e.g. Form2 uses Form1: then you can explicitly pass a reference after creating the forms, bu before you start doing anything with them.
//Define a property on TForm2 E.g.
property MainForm: TForm1 read FMainForm write SetMainForm;
//Immediately after creating both forms tell form2 which to use as its main form.
LForm2.MainForm := LForm1;

Salesforce: CallReport trigger is not firing - Tests failing

I am trying to deploy a small change to the trigger and I am getting warnings about insufficient (0%) Unit test coverage for another trigger (setTitle as shown below)
There is a test in place for this (please see below) but for some reason it is not getting taken into account. This test is defined similar to other tests which run successfully but in this case the trigger is not getting invoked (leading to the warnings for insufficient coverage)
Any ideas or suggestions where I can look and if there is any way to get past the test?
Trigger Test:
Call_Report__c c = new Call_Report__c(name='test cr', opportunity__c=o.id);
insert c;
Trigger declaration:
trigger setTitle on Call_Report__c (before insert)
Thank you!
I think the best way would be to try running the unit test manually in your target org and examine the debug log. And also manually check from UI if functionality still behaves as expected.
Some tips:
(applicable only when deploying to sandboxes) As stupid as it sounds are you sure the trigger is active? There's a checkbox when you edit them from UI or a status field in the accompanying metadata xml
Similar checkbox - is the trigger valid? If it was calling a method from class that was modified in the meantime you'll have a problem.
Do you have any recently introduced validations on the Call_Report__c or any prerequisites used in the test (like Opportunity):
fields marked as required in field definition,
shortened text field size but you're passing a too long string
Validation Rules (not on the Call_Report__c because these are checked later), but on Opportunity etc.
Can you add some system.debug() to the test to make sure that Opportunity you're using is created ok. Also - sometimes developers are too much VF-centered and don't throw exceptions but swallow them and put VF error messages so check ApexPages.hasMessages() too.
(more and more stupid stuff at that point) ;) Class and function are marked as isTest / testmethod? Is that the only trigger on the object? If there are more before insert - you can't guarantee the order, maybe something fails over there?
...

Delphi: App initialization - best practices / approach

I run into this regularly, and am just looking for best practice/approach. I have a database / datamodule-containing app, and want to fire up the database/datasets on startup w/o having "active at runtime" set to true at design time (database location varies). Also run a web "check for updates" routine when the app starts up.
Given TForm event sequences, and results from various trial and error, I'm currently using this approach:
I use a "Globals" record set up in the main form to store all global vars, have one element of that called Globals.AppInitialized (boolean), and set it to False in the Initialization section of the main form.
At the main form's OnShow event (all forms are created by then), I test Globals.AppInitialized; if it's false, I run my "Initialization" stuff, and then finish by setting Globals.AppInitialized := True.
This seems to work pretty well, but is it the best approach? Looking for insight from others' experience, ideas and opinions. TIA..
I generally always turn off auto creation of all forms EXCEPT for the main form and possibly the primary datamodule.
One trick that I learned you can do, is add your datamodule to your project, allow it to auto-create and create BEFORE your main form. Then, when your main form is created, the onCreate for the datamodule will have already been run.
If your application has some code to say, set the focus of a control (something you can't do on creation, since its "not visible yet") then create a user message and post it to the form in your oncreate. The message SHOULD (no guarantee) be processed as soon as the forms message loop is processed. For example:
const
wm_AppStarted = wm_User + 101;
type
Form1 = class(tForm)
:
procedure wmAppStarted(var Msg:tMessage); message wm_AppStarted;
end;
// in your oncreate event add the following, which should result in your wmAppStarted event firing.
PostMessage(handle,wm_AppStarted,0,0);
I can't think of a single time that this message was never processed, but the nature of the call is that it is added to the message queue, and if the queue is full then it is "dropped". Just be aware that edge case exists.
You may want to directly interfere with the project source (.dpr file) after the form creation calls and before the Application.Run. (Or even earlier in case.)
This is how I usually handle such initialization stuff:
...
Application.CreateForm(TMainForm, MainForm);
...
MainForm.ApplicationLoaded; // loads options, etc..
Application.Run;
...
I don't know if this is helpful, but some of my applications don't have any form auto created, i.e. they have no mainform in the IDE.
The first form created with the Application object as its owner will automatically become the mainform. Thus I only autocreate one datamodule as a loader and let this one decide which datamodules to create when and which forms to create in what order. This datamodule has a StartUp and ShutDown method, which are called as "brackets" around Application.Run in the dpr. The ShutDown method gives a little more control over the shutdown process.
This can be useful when you have designed different "mainforms" for different use cases of your application or you can use some configuration files to select different mainforms.
There actually isn't such a concept as a "global variable" in Delphi. All variables are scoped to the unit they are in and other units that use that unit.
Just make the AppInitialized and Initialization stuff as part of your data module. Basically have one class (or datamodule) to rule all your non-UI stuff (kind of like the One-Ring, except not all evil and such.)
Alternatively you can:
Call it from your splash screen.
Do it during log in
Run the "check for update" in a background thread - don't force them to update right now. Do it kind of like Firefox does.
I'm not sure I understand why you need the global variables? Nowadays I write ALL my Delphi apps without a single global variable. Even when I did use them, I never had more than a couple per application.
So maybe you need to first think why you actually need them.
I use a primary Data Module to check if the DB connection is OK and if it doesn't, show a custom component form to setup the db connection and then loads the main form:
Application.CreateForm(TDmMain, DmMain);
if DmMain.isDBConnected then
begin
Application.CreateForm(TDmVisualUtils, DmVisualUtils);
Application.CreateForm(TfrmMain, frmMain);
end;
Application.Run;
One trick I use is to place a TTimer on the main form, set the time to something like 300ms, and perform any initialization (db login, network file copies, etc). Starting the application brings up the main form immediately and allows any initialization 'stuff' to happen. Users don't startup multiple instances thinking "Oh..I didn't dbl-click...I'll do it again.."