Cartesian Plane Lesson 18 Page 20: ProfileEditorDialog JUnit Test

JUnit, GUIs, ProfileEditorDialog, ProfileEditorDialogTest

We will implement a JUnit test for the ProfileEditorDialog class on this page.

See also:

GitHub repository: Cartesian Plane Lesson 18

Previous page: Cartesian Plane Lesson 18 Page 19: ProfileEditorDialog Test GUI

Class ProfileEditorDialogTest

What do we have to test when we concentrate on the ProfileEditorDialog? The dialog covers a lot of ground, but:

  • We have verified that the GraphManager, which translates Profile properties into graphics, works as intended.
  • We have verified that updates to Profile properties are correctly passed from the ProfileEditor to the ProfileEditorFeedback panel, which correctly passes them to the GraphManager.
  • We have verified that the ProfileEditor works as intended.
  • We have verified that the ProfileFileManager works as intended.

To complete testing the dialog, all we have left of consequence is to verify what happens when the buttons in the control panel at the bottom of the dialog are clicked (yes, we also have to test the constructor and a couple of other miscellaneous methods, but those are trivial). And the tests for the buttons are all going to be very similar. For example, here’s the pseudocode for the Reset button test:

  1. Verify that the GUI components encapsulate the property values in the base profile.
  2. Change the values of all the GUI components.
  3. Verify that the GUI components encapsulate the new properties.
  4. Click the reset button.
  5. Verify that the component values have reverted to those encapsulated in the base profile.
  6. Verify that clicking the Reset button did not close the dialog.
  7. Close the dialog.

On that note, let’s begin our discussion of the ProfileEditorDialogTest class with its infrastructure. Afterward, we’ll move on to the class’s principal test methods.

ProfileEditorDialogTest Infrastructure

Below, we’ll discuss the ProfileEditorDialogTest class’s fields, helper methods, and before- and after-methods.

⬛ Fields
Here is an annotated list of the ProfileEditorDialogTest class’s variables.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class ProfileEditorDialogTest
{
    private static final File       distinctFile    = 
        ProfileFileManagerTestData.getDistinctFile();
    private static final File       adHocFile       = 
        ProfileFileManagerTestData.getAdhocFile();
    private static final File       readOnlyFile    = 
        ProfileFileManagerTestData.getReadonlyFile();
    private static final File       noSuchFile      = 
        ProfileFileManagerTestData.getNosuchFile();
    
    private static final Profile    baseProfile     =
        ProfileFileManagerTestData.getBaseProfile();
    private static final Profile    distinctProfile = 
        ProfileFileManagerTestData.getDistinctProfile();
    private static final Profile    profile         = new Profile();
    private static final ProfileEditorDialogTestGUI testGUI = 
        ProfileEditorDialogTestGUI.getTestGUI( profile );
    // ...
}
  • Lines 3-10: References to test data files, declared here for convenience. See also the ProfileFileManagerTestData Class:
    • Lines 3,4: File containing unique Profile properties. Never modified.
    • Lines 5,6: File for use as needed by test methods.
    • Lines 7,8: Read-only file used for testing error paths in output operations.
    • Lines 9,10: Nonexistent file for testing error paths in input operations.
  • Lines 12,13: The base profile, containing Profile property values reflected in the PropertyManager when program execution begins. It is never modified. It is used in the beforeEach method to return the PropertyManager to its original state before executing a test method.
  • Lines 14,15: Profile containing property values distinct from those in the baseProfile. It is never modified.
  • Line 16: This is the working profile, to be modified as needed during testing. It is restored to its default values in the beforeEach method. It is the Profile shared with the ProfileEditor and the ProfileEditorDialog.
  • Lines 17,18: Instantiation of ProfileEditorDialogTestGUI for assistance with managing the ProfileEditorDialog GUI.

⬛ Private Methods
Following is a discussion of the ProfileEditorDialogTest class’s helper methods.

🟦 private void applyDistinctFontProperties()
This method changes the values of all components related to font properties. Here’s the annotated code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
private void applyDistinctFontProperties()
{
    Thread              thread  = testGUI.editFont();
    GraphPropertySet    props   = distinctProfile.getMainWindow();
    int                 rgb     =
        props.getFGColor().getRGB() & 0xFFFFFF;
    testGUI.setFGColor( rgb );
    testGUI.setFontBold( props.isBold() );
    testGUI.setFontItalic( props.isItalic() );
    testGUI.setFontDraw( props.isFontDraw() );
    testGUI.setFontName( props.getFontName() );
    testGUI.setFontSize( props.getFontSize() );
    testGUI.selectFDOK();
    Utils.join( thread );
}
  • Line 3: Start the FontEditorDialog. This is necessary to make sure all of its components are initialized.
  • Line 4: Get distinct values for all properties related to the GraphPropertySetMW.
  • Lines 5,6: Get the integer value for the font color.
  • Lines 7-12: Initialize with new values all GUI components that edit properties in the GraphPropertySetMW.
  • Line 13: Dismiss the FontEditorDialog.
  • Line 14: Wait for the FontEditorDialog to close.

🟦 private void applyDistinctGraphProperties()
This method changes the values of all components related to GraphPropertySetMW properties that are not managed via the FontEditorDialog. Here’s the code.

private void applyDistinctGraphProperties()
{
    GraphPropertySet    props   = distinctProfile.getMainWindow();
    int                 rgb     =
        props.getBGColor().getRGB() & 0xFFFFFF;
    testGUI.setBGColor( rgb );
    testGUI.setFontDraw( props.isFontDraw() );
    testGUI.setGridWidth( props.getWidth() );
    applyDistinctFontProperties();
}

🟦 private void applyDistinctLineProperties( String name )
For the given LinePropertySet (name), this method changes the values of all components that edit the encapsulated properties. Only properties that are supported by the target LinePropertySet are modified. Here’s the code.

private void applyDistinctLineProperties( String name )
{
    LinePropertySet props   = 
        distinctProfile.getLinePropertySet( name );
    if ( props.hasColor() )
    {
        int rgb = props.getColor().getRGB() & 0xffffff;
        testGUI.setColor( name, rgb );
    }
    if ( props.hasDraw() )
        testGUI.setDraw( name, props.getDraw() );
    if ( props.hasLength() )
        testGUI.setLength( name, props.getLength() );
    if ( props.hasSpacing() )
        testGUI.setSpacing( name, props.getSpacing() );
    if ( props.hasStroke() )
        testGUI.setStroke( name, props.getStroke() );
}

🟦 private void applyDistinctProperties()
This method changes the values of all components used to edit Profile properties to new values. The code looks like this.

private void applyDistinctProperties()
{
    testGUI.setGridUnit( distinctProfile.getGridUnit() );
    testGUI.setName( distinctProfile.getName() );
    applyDistinctGraphProperties();
    Stream.of( 
        "LinePropertySetGridLines",
        "LinePropertySetAxes",
        "LinePropertySetTicMajor",
        "LinePropertySetTicMinor"
    )
        .forEach( this::applyDistinctLineProperties );
}

🟦 private void waitOp()
The waitOp method is only used for debugging. It posts a modal dialog, suspending the test thread and freezing the GUI until the dialog is dismissed. A listing for this method follows.

@SuppressWarnings("unused")
private void waitOp()
{
    JOptionPane.showMessageDialog( null, "Waiting" );
}

🟦 public void beforeEach() throws Exception
This method is executed each time a test method is invoked. It returns the PropertyManager, ProfileEditor, and working Profile to their initial states. The annotated code follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@BeforeEach
public void beforeEach() throws Exception
{
    baseProfile.apply();
    profile.reset();
    
    testGUI.reset();
    
    assertEquals( baseProfile, profile );
    Profile testProfile = testGUI.getComponentValues();
    assertEquals( profile, testProfile );
}
  • Line 4: Return the PropertyManager to its initial state.
  • Line 5: Return the working Profile to its initial state.
  • Line 7: Return the ProfileEditor GUI components to their initial state.
  • Line 9: Sanity check; verify that the working profile is in the expected state.
  • Lines 10,11: Sanity check; verify that the ProfileEditor components are in the expected state.

🟦 public void afterEach()
This method is executed each time a test method is completed. If the test fails, leaving a dialog posted, this method will dismiss it. It looks like this:

@AfterEach
public void afterEach()
{
    testGUI.cancelDialog();
}

🟦 @AfterAll public static void afterAll()
This method is executed after all tests are completed. It returns the PropertyManager to its original state, which is required if this JUnit test class is included in a test suite. It disposes all top-level windows and deletes the test files. Here’s the code.

@AfterAll
public static void afterAll()
{
    baseProfile.apply();
    ComponentFinder.disposeAll();
    ProfileFileManagerTestData.shutdown();
}

🟦 private static void saveProfile( Profile profile, File file )
This method saves a profile to a file without changing the state of the ProfileFileManager. (Note: a better place for this method would be ProfileFileManagerTestData.) Here’s the code.

private static void saveProfile( Profile profile, File file ) 
{
    ProfileParser   parser      = new ProfileParser( profile );
    try ( 
        FileOutputStream fileStr = new FileOutputStream( file );
        PrintWriter writer = new PrintWriter( fileStr );
    )
    {
        parser.getProperties().forEach( writer::println );
    }
    catch ( IOException exc )
    {
        fail( "Unexpected I/O exception", exc );
    }
}

⬛ JUnit Test Methods
Following are the principal test methods for this class.

🟦 public void testProfileEditorDialog()
🟦 public void testGetProfileEditor()
The methods test the ProfileEditorDialog constructor and the ProfileEditorDialog’s getProfileEditor methods. They are very simple, as seen below.

@Test
public void testProfileEditorDialog()
{
    // If it doesn't crash, it passes.
    new ProfileEditorDialog( null,new Profile() );
}
@Test
public void testGetProfileEditor()
{
    ProfileEditorDialog dialog  = 
        new ProfileEditorDialog( null,new Profile() );
    assertNotNull( dialog.getProfileEditor() );
}

🟦 public void testResetFromBase()
This is one of two tests for the dialog Reset function. It sets the GUI components to distinct values, pushes the Reset button when no file is open, and verifies that the encapsulated ProfileEditor is refreshed from the PropertyManager. Here is the annotated code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void testResetFromBase()
{
    Thread  thread              = testGUI.postDialog();
    Profile startProps          = testGUI.getComponentValues();
    assertEquals( baseProfile, startProps );
    applyDistinctProperties();
    Profile testDistinctProps   = testGUI.getComponentValues();
    assertEquals( testDistinctProps, distinctProfile );
    
    testGUI.pushCloseButton();
    testGUI.pushResetButton();
    Profile testResetProps      = testGUI.getComponentValues();
    
    assertTrue( testGUI.isVisible() );
    
    testGUI.pushCancelButton();
    Utils.join( thread );
    
    assertFalse( testGUI.isVisible() );
    assertEquals( baseProfile, testResetProps );
}
  • Line 4: Start the ProfileEditorDialog.
  • Lines 5,6: Sanity check; verify that the ProfileEditor components are in the expected state.
  • Line 7: Change the values of all ProfileEditor components that encapsulate Profile properties.
  • Lines 8,9: Sanity check; verify that the ProfileEditor components are in the expected state.
  • Line 11: If necessary, close the open file.
  • Line 12: Push the Reset button.
  • Line 13: Get the values of the ProfileEditor components.
  • Line 15: Verify that pushing the Reset button did not close the dialog.
  • Lines 17,18: Cancel the dialog and wait for it to close.
  • Line 20: Verify that pushing the dialog’s Cancel button closed the dialog.
  • Line 21: Verify that the ProfileManager has been reset to the expected values.

🟦 public void testResetFromFile()
This is the second of two tests for the dialog Reset function. It sets the GUI components to distinct values and saves them to a file, leaving the file open. Then, it changes the GUI components to their base values, pushes the Reset button, and verifies that the encapsulated ProfileEditor is refreshed from the open file. Here is the annotated code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
public void testResetFromFile()
{
    Thread  thread      = testGUI.postDialog();
    saveProfile( baseProfile, adHocFile );
    testGUI.openFile( adHocFile );
    
    Profile testProfile = testGUI.getComponentValues();
    File    testFile    = testGUI.getCurrFile();
    assertEquals( baseProfile, testProfile );
    ProfileFileManagerTestData.compareFileNames( adHocFile, testFile );
    
    saveProfile( distinctProfile, adHocFile );
    testGUI.pushResetButton();
    testProfile = testGUI.getComponentValues();
    assertEquals( distinctProfile, testProfile );
    
    assertTrue( testGUI.isVisible() );
    
    testGUI.pushCancelButton();
    Utils.join( thread );
    
    assertFalse( testGUI.isVisible() );
}
  • Line 4: Start the ProfileEditorDialog.
  • Line 5: Write the baseProfile to adHocFile without going through the ProfileFileManager.
  • Line 6: Open adHocFile via the ProfileEditorDialog.
  • Lines 8-11: Sanity check; verify that the GUI agrees with the baseProfile and that the adHocFile is open.
  • Line 13: Write distinctProfile to adHocFile without affecting the GUI or the ProfileFileManager state.
  • Line 14: Push the Reset button.
  • Lines 15,16: Verify that the distinct property values have been read from adHocFile into the GUI components.
  • Line 18: Verify that pushing the Reset button did not dismiss the ProfileEditorDialog.
  • Lines 20,21: Cancel the ProfileEditorDialog and wait for it to close.
  • Line 23: Verify that the ProfileEditorDialog has been dismissed.

🟦 public void testApply()
The testApply method enters distinct values into the ProfileEditor, then pushes the ProfileEditorDialog’s Apply button, verifying that the distinct values have been written to the PropertyManager. The annotated code follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@Test
public void testApply()
{
    Thread  thread              = testGUI.postDialog();
    Profile startProps          = testGUI.getComponentValues();
    assertEquals( baseProfile, startProps );
    
    applyDistinctProperties();
    Profile testDistinctProps   = testGUI.getComponentValues();
    assertEquals( distinctProfile, testDistinctProps );
    
    testGUI.pushApplyButton();
    Profile testCommittedProps  = new Profile();
    assertEquals( testDistinctProps, testCommittedProps );
    
    assertTrue( testGUI.isVisible() );
    
    testGUI.pushCancelButton();
    Utils.join( thread );
}
  • Line 4: Start the ProfileEditorDialog.
  • Lines 5,6: Sanity check; verify that the initial values of the ProfileEditor components agree with the baseProfile.
  • Line 8: Set the ProfileEditor components to distinct values.
  • Lines 9,10: Sanity check; verify that the ProfileEditor components have the expected values.
  • Line 12: Push the dialog’s Apply button.
  • Line 13: Get a new Profile, initialized to values from the PropertyManager.
  • Line 14: Verify that the new Profile contains distinct property values.
  • Line 16: Verify that pushing the Apply button did not close the dialog.
  • Lines 18,19: Push the dialog’s Cancel button and wait for it to close.

🟦 public void testOK()
The testOK button is very similar to the testApply method. The main difference is that pushing the OK button should update the PropertyManager and then close the dialog. The implementation of this method is an exercise for the student. The solution is in the GitHub repository.

🟦 public void testCancel()
To test the dialog’s Cancel facility, we start the dialog and set the ProfileEditor components to distinct values. Then, we push the Cancel button, verifying that it closes the dialog and does not update the PropertyManager. Next, we restart the dialog and verify that the ProfileEditor contains the same property values as those in baseProfile. Following is an annotated listing for the testCancel method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Test
public void testCancel()
{
    Thread  thread              = testGUI.postDialog();
    Profile startProps          = testGUI.getComponentValues();
    assertEquals( baseProfile, startProps );
    
    applyDistinctProperties();
    Profile testDistinctProps   = testGUI.getComponentValues();
    assertEquals( distinctProfile, testDistinctProps );
    
    testGUI.pushCancelButton();
    Utils.join( thread );
    assertFalse( testGUI.isVisible() );
    int     lastResult  = testGUI.getLastDialogResult();
    assertEquals( JOptionPane.CANCEL_OPTION, lastResult );
    
    Profile testCommittedProps  = new Profile();
    assertEquals( baseProfile, testCommittedProps );
    
    thread = testGUI.postDialog();
    Profile testProps   = testGUI.getComponentValues();
    assertEquals( baseProfile, testProps );

    testGUI.pushCancelButton();
    Utils.join( thread );
}
  • Lines 4-6: Start the ProfileEditorDialog and verify that the ProfileEditor reflects the expected property values.
  • Lines 8-10: Assign distinct values to the ProfileEditor components and verify that they are correctly set.
  • Line 12: Push the dialog’s Cancel button.
  • Line 13: Wait for the dialog to close.
  • Line 14: Verify that the dialog has been dismissed.
  • Lines 15,16: Validate the lastAction property of the ProfileFileManager.
  • Lines 18,19: Verify that the distinct values assigned to the ProfileEditor (line 8) have not been committed to the PropertyManager.
  • Lines 21-23: Restart the dialog and verify that the ProfileEditor is initialized with the expected properties.
  • Lines 25,26: Push the dialog’s Cancel button and wait for it to close.

🟦 public void testOpen()
The main thread of this test is to start the ProfiileEditorDialog, open distinctFile, and verify that the ProfileEditor components are set to values encapsulated in distinctProfile. Here’s the code.

@Test
public void testOpen()
{
    // Start the dialog
    Thread  thread      = testGUI.postDialog();
    // Sanity check; verify the initial values of the ProfileEditor
    Profile startProps  = testGUI.getComponentValues();
    assertEquals( baseProfile, startProps );

    // Open distinctfile and verify that the ProfileEditor
    // now contains distinct values.
    testGUI.openFile( distinctFile );
    Profile currProps   = testGUI.getComponentValues();
    assertEquals( distinctProfile, currProps );
    
    // Push the dialog's Cancel button, wait for it to be dismissed,
    // and verify that it is closed.
    testGUI.pushCancelButton();
    Utils.join( thread );
    assertFalse( testGUI.isVisible() );
}

🟦 public void testOpenGoWrong()
The testOpenGoWrong method attempts to open a non-existent file, verifies that it gets an I/O error, and validates the subsequent state of the dialog. Below, find an annotated listing of this method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@Test
public void testOpenGoWrong()
{
    Thread  thread      = testGUI.postDialog();
    applyDistinctProperties();
    Profile startProps  = testGUI.getComponentValues();
    assertEquals( distinctProfile, startProps );
    
    testGUI.openFileGoWrong( noSuchFile );
    Profile currProps   = testGUI.getComponentValues();
    assertEquals( distinctProfile, currProps );

    testGUI.pushCancelButton();
    Utils.join( thread );
    assertFalse( testGUI.isVisible() );
}
  • Line 4: Start the dialog.
  • Lines 5-7: Apply distinct values to the ProfileEditor and verify they are applied correctly.
  • Line 9: Attempt to open a non-existent file.
  • Lines 10,11: Verify that the ProfileEditor has not changed.
  • Lines 13-15: Cancel the dialog and wait for it to close.

🟦 public void testSaveNoOpenFile()
This method verifies the dialog’s behavior when the Save button is pushed while no file is open. The annotated code for testSaveNoOpenFile follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@Test
public void testSaveNoOpenFile()
{
    Thread  thread      = testGUI.postDialog();
    Profile startProps  = testGUI.getComponentValues();
    assertEquals( baseProfile, startProps );
    
    adHocFile.delete();
    assertFalse( adHocFile.exists() );
    testGUI.pushCloseButton();
    
    testGUI.save( adHocFile );
    assertTrue(
        ProfileFileManagerTestData
            .validateFile( baseProfile, adHocFile )
    );
    testGUI.pushCancelButton();
    Utils.join( thread );
}
  • Lines 4-6: Start the ProfileEditorDialog and verify the initial values of the ProfileEditor.
  • Lines 8-10: Make sure adHocFile doesn’t exist and there is no open file.
  • Lines 12-16: Push the Save button, then verify that adHocFile exists and contains the expected property values.
  • Lines 17,18: Cancel the dialog and wait for it to close.

🟦 public void testSaveOpenFile()
This method verifies the dialog’s behavior when its Save button is pushed while a file is open. The test works like this:

  • Start the ProfileEditorDialog; the ProfileEditor will initially reflect the properties in baseProfile.
  • Save the profile to the adHocFile.
  • Change the values of the ProfileEditor components to distinct values.
  • Push the Save button.
  • Verify that the adHocFile contains distinct property values.

The implementation of this method is an exercise for the student. The solution is in the GitHub repository.

🟦 public void testSaveGoWrongNoOpenFile()
This method verifies the dialog’s behavior when its Save button is pushed while no file is open and an I/O error is expected. Here’s an outline of the test:

  • Start the ProfileEditorDialog.
  • Push the Close button to make sure there is no open file.
  • Apply distinct property values to the ProfileEditor.
  • Try to save to the readOnlyFile (testGUI.saveGoWrong(readOnlyFile).
  • Cancel the dialog and wait for it to close.
  • Verify that readOnlyFile has not been changed.

The implementation of this method is an exercise for the student. The solution is in the GitHub repository.

🟦 public void testSaveGoWrongOpenFile()
This method verifies the dialog’s behavior when its Save button is pushed while a file is open and an I/O error is expected. The main difference between this method and testSaveGoWrongNoOpenFile is that we will open readOnlyFile instead of pushing the Close File button. The implementation is an exercise for the student. The solution is in the GitHub repository.

🟦 public void testSaveAs()
This method verifies the dialog’s behavior when its Save As button is pushed. To implement the test:

  • Start the ProfileEditorDialog
  • Delete the adHocFile.
  • Push the Save As button, specifying adHocFile as the destination file (testGUI.saveAs(adHocFile)).
  • Cancel the dialog and wait for it to close.
  • Verify that adHocFile exists and contains the property values from the baseProfile.

The implementation of testSaveAs is an exercise for the student. The solution is in the GitHub repository.

🟦 public void testSaveAsGoWrong()
This method verifies the dialog’s behavior when its Save As button is pushed, and an I/O error is expected. The design of this test is very similar to testSaveAs, but instead of saving to adHocFile save to readOnlyFile (testGUI.saveAsGoWrong(readOnlyFile)). Close the dialog and verify the readOnlyFile hasn’t been modified. The implementation is an exercise for the student. The solution is in the GitHub repository.

🟦 public void testCancelFile()
For every operation that requires operator interaction with the file chooser, this method starts an operation, cancels it in the file chooser, and verifies that the state of the dialog’s encapsulated file manager hasn’t changed. Here is an annotated listing.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Test
public void testCancelFile()
{
    Thread  thread      = testGUI.postDialog();
    testGUI.saveAs( adHocFile );
    assertTrue(
        ProfileFileManagerTestData
            .compareFileNames( adHocFile, testGUI.getCurrFile() )
    );
    assertTrue(
        ProfileFileManagerTestData
            .validateFile( baseProfile, adHocFile )
    );
    testGUI.pushCloseButton();
    assertNull( testGUI.getCurrFile() );

    applyDistinctProperties();
    // sanity check
    Profile currProps   = testGUI.getComponentValues();
    assertEquals( distinctProfile, currProps );
    
    testGUI.cancel( adHocFile, testGUI::pushOpenButton );
    assertNull( testGUI.getCurrFile() );
    currProps = testGUI.getComponentValues();
    assertEquals( distinctProfile, currProps );
    assertTrue(
        ProfileFileManagerTestData
            .validateFile( baseProfile, adHocFile )
    );
    
    testGUI.cancel( adHocFile, testGUI::pushSaveAsButton );
    assertNull( testGUI.getCurrFile() );
    assertTrue(
        ProfileFileManagerTestData
            .validateFile( baseProfile, adHocFile )
    );
    
    testGUI.cancel( adHocFile, testGUI::pushSaveButton );
    assertNull( testGUI.getCurrFile() );
    assertTrue(
        ProfileFileManagerTestData
            .validateFile( baseProfile, adHocFile )
    );

    testGUI.pushCancelButton();
    Utils.join( thread );
}
  • 4-20: Preparation; put the application in a known state before executing the actual tests:
    • Line 4: Start the dialog, which will initialize the ProfileEditor with data from the baseProfile.
    • Line 5: Save the Profile to adHocFile.
    • Lines 6-9: Validate that adHocFile is open.
    • Lines 10-13: Verify the contents of adHocFile.
    • Line 14: Push the dialog’s Close File button.
    • Line 15: Verify that no file is open.
    • Line 17: Apply distinct property values to the ProfileEditor.
    • Lines 19,20: Verify the application of distinct values.
  • Lines 22-29: Start and cancel an Open File operation:
    • Line 22: Push the Open File button and cancel the operation via the file chooser.
    • Line 23: Verify that the file manager’s open file property hasn’t changed.
    • Lines 26-29: Verify that adHocFile hasn’t changed.
  • Lines 31-36: Start and cancel a Save As operation:
    • Line 31: Push the Save As button and cancel the operation via the file chooser.
    • Line 32: Verify that the file manager’s open file property hasn’t changed.
    • Lines 33-36: Verify that adHocFile hasn’t changed.
  • Lines 38-43: With no file open, start and cancel a Save operation:
    • Line 38: Push the Save button and cancel the operation via the file chooser.
    • Line 39: Verify that the file manager’s open file property hasn’t changed.
    • Lines 40-43: Verify that adHocFile hasn’t changed.

🟦 public void testCloseFile()
The testCloseFile method validates the dialog’s Close File operation as follows:

  • Start the ProfileEditorDialog.
  • Open distinctFile (testGUI.openFile(distinctFile)).
    • Verify that the file manager sees distinctFile as open.
    • Verify that the values of the components in the ProfileEditor reflect the property values from distinctProfile.
  • Push the dialog’s close button (testGUI.pushCloseButton()).
  • Verify that the file manager’s open-file property is null.
  • Cancel the dialog and wait for it to close.

The implementation of this method is an exercise for the student. The solution is in the GitHub repository.

Summary

On this page, we implemented a JUnit test for the ProfileEditorDialog. Our final task is to integrate it with the application menu bar.

Next: Application Menubar Integration