diff --git a/output/info202_labs.html b/output/info202_labs.html index e0f89c2..f916228 100644 --- a/output/info202_labs.html +++ b/output/info202_labs.html @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:119d4343a26208e4af2559821d373957056ff0d26d64f116d6bcf8b9fefccb71 -size 4587285 +oid sha256:2e17bac634ad09adf13e8f2e5566698c94553de42bb5798796f7e90698e1ad35 +size 4583389 diff --git a/tiddlers/content/_Coursework.tid b/tiddlers/content/_Coursework.tid index f43e972..2ee5219 100644 --- a/tiddlers/content/_Coursework.tid +++ b/tiddlers/content/_Coursework.tid @@ -31,7 +31,7 @@ <> !!! Testing -<> +<> !!! Software used in {{$:/ou/parameters/Paper Code}} <> diff --git a/tiddlers/content/labs/lab02/_Labs_02_Initial Set-Up.md b/tiddlers/content/labs/lab02/_Labs_02_Initial Set-Up.md index 6b48ae7..585cdbb 100644 --- a/tiddlers/content/labs/lab02/_Labs_02_Initial Set-Up.md +++ b/tiddlers/content/labs/lab02/_Labs_02_Initial Set-Up.md @@ -16,9 +16,9 @@ ```java dependencies { def junitVer = "5.8.2"; - testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junitVer; - testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: junitVer; - testImplementation group: 'org.hamcrest', name: 'hamcrest', version: '2.2'; + testImplementation group: "org.junit.jupiter", name: "junit-jupiter-api", version: junitVer; + testRuntimeOnly group: "org.junit.jupiter", name: "junit-jupiter-engine", version: junitVer; + testImplementation group: "org.hamcrest", name: "hamcrest", version: "2.2"; } ``` diff --git a/tiddlers/content/labs/lab03/_Labs_03_Check Your Branches.md b/tiddlers/content/labs/lab03/_Labs_03_Check Your Branches.md deleted file mode 100644 index 5fa12f8..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Check Your Branches.md +++ /dev/null @@ -1,14 +0,0 @@ -A quick survey of the Git repositories on GitBucket shows that several of you have not merged your `topic/product_editor` branch into `master` yet. This is going to cause problems, so you should check and fix this. - -1. Open NetBeans and look at the root of the project in the projects pane. You will see the current branch to the right of the project name. If you have properly merged the branch then: - - * The current branch should be `[master]`. - * You should be able to see your `ProductEditor` class in the `gui` package. It should be the latest version with the completed <> button click handler. - - If this is true then you are all good and can move on with the rest of the lab. - -2. If your project is currently on the `[topic/product_editor]` branch then work through steps 1 --- 10 of section [4.2.2](#/Labs/02/Merging%20Topic%20Branches) of last week's lab again since you might have missed one of those steps. Repeating steps that you have already performed will not cause any trouble. - -We found ourselves drawing a diagram for several students in last week's lab while explaining the merge process --- we probably should have included a diagram in last week's lab (we have now retroactively added it to lab 2). Here it is now: - -{{/Labs/02/images/Merging Topic Branches}} \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Check Your Branches.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Check Your Branches.md.meta deleted file mode 100644 index 26b0029..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Check Your Branches.md.meta +++ /dev/null @@ -1,4 +0,0 @@ -section: 3 -tags: lab03 hidden -title: $:/Labs/03/Check Your Branches -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Displaying the Main Menu.md b/tiddlers/content/labs/lab03/_Labs_03_Displaying the Main Menu.md deleted file mode 100644 index 54d96da..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Displaying the Main Menu.md +++ /dev/null @@ -1,17 +0,0 @@ -You should have created the `MainMenu` frame as part of the project task from last week's lab. If you have not yet created this frame, then do so now. - -There are two things that need to happen for the `MainMenu` to be useful: - -1. The `Main` class that you created in the last lab should create and display an instance of the `MainMenu` frame. - - Refer to the reference section for information on how to do this ([Swing/Displaying Frames](#/Reference/Swing/Displaying%20Frames)) - -1. The button handlers for the buttons on the main menu should perform the appropriate actions: - - The <> button should call `System.exit(0)` to exit the system. The 0 is an exit code that usually implies that the program exited normally. Numbers greater than 0 imply that the program exited due to an error. - - The other buttons should display the appropriate dialog. We only have the `ProductEditor` dialog to link at this point --- the next section will show you how to do this. - -Test the system by running the `Main` class. You should see the `MainMenu` appear. The <> button should quit the application. - -Now would be a good time to commit. Remember to reference the issue that relates to creating the Main Menu in your commit message. \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Displaying the Main Menu.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Displaying the Main Menu.md.meta deleted file mode 100644 index d651218..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Displaying the Main Menu.md.meta +++ /dev/null @@ -1,3 +0,0 @@ -section: 4.1 -title: $:/Labs/03/Displaying the Main Menu -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Displaying the Products.md b/tiddlers/content/labs/lab03/_Labs_03_Displaying the Products.md deleted file mode 100644 index 3c2b44e..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Displaying the Products.md +++ /dev/null @@ -1,33 +0,0 @@ -Now we need to make the `ProductViewer` display the products that have been saved in the DAO. - -1. In the source view, add a field to `ProductViewer` that is an instance of your DAO class. - -1. We need to get the product objects out of the DAO and put them into the `JList`. - - Since Swing components use the Model-View-Controller mechanism, we need to create a *model* (not to be confused with *modal* --- they are two entirely different concepts) that will hold the data and then tell the list component about the model. - - The default model classes in Swing are outdated and clunky, so we have written one that is a bit easier to work with: - - 1. Create a new class named `SimpleListModel`. It should go in a package named `helpers` - - 1. Open the following URL in a web browser: - - https://isgb.otago.ac.nz/info202/shared/useful-files/blob/master/helpers/SimpleListModel.java - - 1. Copy and paste the code into your `SimpleListModel` class. - -1. Refer to the [Swing/List Components (JList and JComboBox)/Displaying Objects in a List](#/Reference/Swing/List%20Components%20(JList%20and%20JComboBox)/Displaying%20Objects%20in%20a%20List) section in the reference. - - Add a `SimpleListModel` **field** to your `ProductViewer` dialog (step 1 from the reference). This model is for holding the products that will be displayed so name it `productsModel`. - - Call the method on the DAO object that gets all of the products. Store the result in a variable. - - Update the contents of the model field using the list of products that you just retrieved from the DAO (step 2 in the reference). - - Tell the `JList` component about the model (step 3). - -1. Test the system again. You should now be able to add some products using the product editor dialog and then see them in the product viewer dialog. - - If you are not happy with how the products are being displayed then you can change the `toString()` method in the product domain class. - -1. You can close the issue for this feature now. \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Displaying the Products.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Displaying the Products.md.meta deleted file mode 100644 index 4f723fa..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Displaying the Products.md.meta +++ /dev/null @@ -1,4 +0,0 @@ -section: 6.1 -tags: lab03 hidden -title: $:/Labs/03/Displaying the Products -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Examine the StudentEditorTest.md b/tiddlers/content/labs/lab03/_Labs_03_Examine the StudentEditorTest.md new file mode 100644 index 0000000..bfadcff --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_Examine the StudentEditorTest.md @@ -0,0 +1,59 @@ +The tests in the `gui` package in the <> source folder should compile now. The `StudentEditorTest` is complete. You will be completing the `StudentViewerTest`. + +1. Run the tests using < Test">> and then let go of the mouse. Seriously --- take your hand off the mouse. + + You should see the AssertJ robot start clicking and typing. That is why you needed to let go of the mouse --- if you jiggled it while the robot was doing its thing you might cause it to miss what it was aiming at. + + We did once watch a student accidentally bump the right mouse button causing the mouse pointer to move over the NetBeans projects pane along with a right-click at the wrong moment and the AssertJ robot managed to select the *Delete* option in the NetBeans project menu. Luckily it didn't also click the <> button to confirm the deletion, but there was some sweating/swearing while we waited for the tests to complete. + + Having said that, the robot is pretty reliable. The above scenario was a complete fluke --- the robot was looking for a <> button on the dialog at the exact moment that the student bumped the mouse, and instead found and clicked on the <> option in the menu that appeared. Even if you do bump the mouse, the chances of it doing something scary to your computer are very slim. The worst that will usually happen is that a test will fail, or the mouse pointer will get stuck and you need to stop the test. + +2. You will likely see some red warnings in the output pane. They are warnings relating to changes to the Java reflection API in newer versions of Java causing potential incompatibilities with some of the libraries we are using. You can ignore them. + +3. Take a look at the `gui.StudentEditorTest` class. + + There is a lot going on in there. It is heavily commented, so you should be able to see what is happening. + + `StudentDAO` is a DAO interface. + + The `@BeforeEach` method is creating a mock DAO object using Mockito. Since the DAO needs to provide majors to display in the majors combo box the `setUp` method creates a `getMajors` stub that returns some hard-coded majors. + + Lines 29--33 are configuring the AssertJ robot. You can slow the robot down further by increasing the delay on line 32. This allows you to see exactly what the robot is doing which is sometimes handy if it isn't doing what you want it to. When you are happy that the tests work you can reduce the delay to speed up the tests --- don't make the delay less than 10 or the robot will be trying to click on things before the GUI has finished initialising them. + + The `testSave` method is using AssertJ to interact with the dialog. + + Let's take a closer look at the save test (`testSave` method). + + Lines 56--60 are creating the dialog and setting up the interaction between the dialog and AssertJ. + + Line 63 tells AssertJ to display the dialog and then also verify that the dialog actually appears. This will catch any errors in the dialog's constructor that cause it to not be displayed. + + Line 67 tells to robot to click on the dialog. This is needed since if you are using multiple monitors and/or virtual desktops then the keyboard focus doesn't always automatically switch to the new dialog. This ensures that the dialog is focused. + + Lines 70--72 instruct the robot to enter values into the text fields and combobox. + + Line 75 instructs the robot to click the <> button. At this point the `btnSaveActionPerformed` handler is executed so new student object should be created and stored in the DAO. + + From that point on the test hands over to Mockito to check the interaction between the dialog and the mock DAO. + + Line 78 sets up a Mockito captor object to grab hold of the student domain object that was created and passed to the DAO via the `save` method. + + Line 81 uses Mockito to check that the DAO `save` method was called and captures the student object that is passed to that method. If the `save` method has not been called at this point then test will fail. + + Line 84 gets a reference to the captured student object from the captor. + + Lines 87--89 use Hamcrest to check that the student object's fields contain the new values that were entered into the GUI by the robot. + + + +We are using four different testing libraries for testing the GUIs. Here is a quick summary of the role of each library: + +* **JUnit** is used to define the test methods (`@Test`, `@BeforeEach`, `@AfterEach`), run the tests, and report the results. + +* **AssertJ Swing** is used to drive the robot (`enterText()`, `selectItem()`, ...) and verify that the components are displaying what we expect them to display (`require...()`) + +* **Mockito** is used to mock the DAO (`mock()`, `when(...).thenReturn(...)`), verify that the DAO methods were called by the GUI (`verify()`), and also get hold of the object that was passed to the DAO methods (`capture()`). + +* **Hamcrest** is used to verify that the details of the saved student matched was was entered into the GUI (`assertThat()`). + +<> The names that AssertJ is using to find the components (txtId, txtName, cmbMajor, and btnSave) are NOT the component's field names. The are the values of the name property for the components. If you look in the constructor for the StudentEditor class you will see where the component names are being set using the setName method. diff --git a/tiddlers/content/labs/lab03/_Labs_03_Examine the StudentEditorTest.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Examine the StudentEditorTest.md.meta new file mode 100644 index 0000000..f663233 --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_Examine the StudentEditorTest.md.meta @@ -0,0 +1,4 @@ +section: 4.2 +tags: lab03 lab +title: /Labs/03/Examine the StudentEditorTest +type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Experimenting with Modal Dialogs.md b/tiddlers/content/labs/lab03/_Labs_03_Experimenting with Modal Dialogs.md deleted file mode 100644 index 5984703..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Experimenting with Modal Dialogs.md +++ /dev/null @@ -1,9 +0,0 @@ -It is important that you understand what a modal dialog is. - -Currently the `MainMenu` is starting the `ProductEditor` in *modal* mode. Test this by running the `Main` class clicking the <> button in the menu. Can you drag the `ProductEditor` dialog out of the way and click the button on the `MainMenu` again? - -Let's make the dialog non-modal. Open the button click handler in the `MainMenu` frame. In the line of code that creates the `ProductEditor` dialog instance change the boolean parameter to `false`. Test the system again. Can you open multiple `ProductEditor` dialogs now? - -This is quite dangerous since we now have to worry about bugs that can be created by having multiple instances of the dialogs being used by the user concurrently. For example, what would happen if the user managed to edit a product and then delete the same product from a different dialog before saving the edited product? Nothing good. - -Change the parameter back to `true` again since we want the dialog to be modal. \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Experimenting with Modal Dialogs.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Experimenting with Modal Dialogs.md.meta deleted file mode 100644 index fbedbd3..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Experimenting with Modal Dialogs.md.meta +++ /dev/null @@ -1,4 +0,0 @@ -section: 4.3 -tags: lab03 hidden -title: $:/Labs/03/Experimenting with Modal Dialogs -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Frames & Dialogs.md b/tiddlers/content/labs/lab03/_Labs_03_Frames & Dialogs.md deleted file mode 100644 index 33bf2cb..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Frames & Dialogs.md +++ /dev/null @@ -1,11 +0,0 @@ -Frames and dialogs differ in the following ways: - -* Dialogs don't appear in the operating system's task bar. Frames do appear in the task bar. - -* Dialogs are usually created by a frame which becomes the owner/parent of the dialog --- if the frame is closed then any dialogs that the frame created will be closed too. - -* Dialogs can be made *modal* which means that the user can not access any other windows until they close the dialog. - -Generally you have one frame that is the main window for the system and all other windows that are created are modal dialogs. This helps make the system significantly easier to create since we don't have to worry about bugs that can occur when the user has access to many dialogs at once. - -In our system, the `MainMenu` frame that you created as a project task last week is the primary window, and all other windows will be modal dialogs. \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Frames & Dialogs.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Frames & Dialogs.md.meta deleted file mode 100644 index e03bc26..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Frames & Dialogs.md.meta +++ /dev/null @@ -1,4 +0,0 @@ -section: 4 -tags: lab03 hidden -title: $:/Labs/03/Frames & Dialogs -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Introduction.md b/tiddlers/content/labs/lab03/_Labs_03_Introduction.md index 2585ce5..54e8b52 100644 --- a/tiddlers/content/labs/lab03/_Labs_03_Introduction.md +++ b/tiddlers/content/labs/lab03/_Labs_03_Introduction.md @@ -1 +1,9 @@ -In this lab we will be completing the dialog that allows the user to create and store a new product, and adding another dialog for viewing all of the products that have been entered so far. +In the last lab, we showed you how to do basic automated testing. There are a couple of other things that you need to know: + +* How to refactor a system to make it easier to test. The primary technique that we will use is known as *inversion of control*. + +* How to use mocks to isolate components. + +* How to drive tests that have user interfaces. + +These topics will be covered in this lab. There are a couple of other testing related topics that will be covered in later labs. diff --git a/tiddlers/content/labs/lab03/_Labs_03_Introduction.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Introduction.md.meta index 1005fb6..54db4db 100644 --- a/tiddlers/content/labs/lab03/_Labs_03_Introduction.md.meta +++ b/tiddlers/content/labs/lab03/_Labs_03_Introduction.md.meta @@ -1,4 +1,4 @@ -section: 2 -tags: lab03 hidden -title: $:/Labs/03/Introduction +section: 1 +tags: lab03 lab +title: /Labs/03/Introduction type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Lab 3_ GUIs, DAOs & Testing.tid b/tiddlers/content/labs/lab03/_Labs_03_Lab 3_ GUIs, DAOs & Testing.tid deleted file mode 100644 index ac61975..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Lab 3_ GUIs, DAOs & Testing.tid +++ /dev/null @@ -1,11 +0,0 @@ -created: 20200702091026430 -modified: 20200707005526287 -tags: lab toc hidden -title: $:/Labs/03/Lab 3: GUIs, DAOs & Testing -type: text/vnd.tiddlywiki - -!! Contents -<$set name="path" value="/Labs/03/"> -<$macrocall $name="contents-tree" path=<> /> -<$macrocall $name="openByPath" path=<> /> -$set> diff --git a/tiddlers/content/labs/lab03/_Labs_03_Lab 3_ Mocks, GUI Testing, and DAO Testing.tid b/tiddlers/content/labs/lab03/_Labs_03_Lab 3_ Mocks, GUI Testing, and DAO Testing.tid new file mode 100644 index 0000000..19b63a6 --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_Lab 3_ Mocks, GUI Testing, and DAO Testing.tid @@ -0,0 +1,9 @@ +tags: lab toc lab03 +title: /Labs/03/Lab 3: Mocks, GUI Testing, and DAO Testing +type: text/vnd.tiddlywiki + +!! Contents +<$set name="path" value="/Labs/03/"> +<$macrocall $name="contents-tree" path=<> /> +<$macrocall $name="openByPath" path=<> /> +$set> diff --git a/tiddlers/content/labs/lab03/_Labs_03_Link the Product Editor to the Main Menu.md b/tiddlers/content/labs/lab03/_Labs_03_Link the Product Editor to the Main Menu.md deleted file mode 100644 index b12f9f5..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Link the Product Editor to the Main Menu.md +++ /dev/null @@ -1,15 +0,0 @@ -When the user clicks the <> button on the main menu, your `ProductEditor` dialog should be displayed. - -1. Add an issue to GitBucket describing this task. - -1. While you are there, add another issue reminding yourself to link the <> button to the product viewer dialog. - -1. Since the product viewer dialog doesn't exist yet, add another issue reminding yourself to create that dialog. You should be treating the issue tracker as a 'to do' list. Provide sufficient detail in your issue descriptions that you will understand what an issue refers to in 3 weeks time (which is long enough for you to have completely forgotten the context for the issue). - -1. Refer to the [Swing/Displaying Dialogs](#/Reference/Swing/Displaying%20Dialogs) section in the reference for the code that you need to display a dialog. - - Double click the button in the `MainMenu` to create the event handler method that you need to add the code to. - -1. Test your work. You should be able to run your `Main` class, have the main menu appear, and then click the button to display the product editor dialog. - -1. Commit. You have completed the issue that you added in the first step, so you can close the issue now. You can add the text `Closes #4` to your commit message (assuming the issue ID was #4) to close the issue automatically. \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Link the Product Editor to the Main Menu.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Link the Product Editor to the Main Menu.md.meta deleted file mode 100644 index df05e71..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Link the Product Editor to the Main Menu.md.meta +++ /dev/null @@ -1,4 +0,0 @@ -section: 4.2 -tags: lab03 hidden -title: $:/Labs/03/Link the Product Editor to the Main Menu -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Milestone 1 is Due on Monday Next Week.md b/tiddlers/content/labs/lab03/_Labs_03_Milestone 1 is Due on Monday Next Week.md deleted file mode 100644 index 0b15cc4..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Milestone 1 is Due on Monday Next Week.md +++ /dev/null @@ -1,7 +0,0 @@ -Milestone 1 is due next Monday (2nd August) at 9:00am - -By the time you have completed this lab and the additional project tasks described in the [Project Tasks](#/Labs/03/Project%20Tasks) section you will have completed the requirements for milestone 1. - -Refer to the project document (section [4.4.1](https://isgb.otago.ac.nz/info202/shared/project/raw/master/output/info202_project.html#%2FMilestones%201%20%26%202%2FMilestone%201)) to verify that your project includes all of the requirements for milestone 1. - -The submission instructions are on Blackboard at < Project > Submission Instructions">>. Please follow those instructions carefully. \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Milestone 1 is Due on Monday Next Week.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Milestone 1 is Due on Monday Next Week.md.meta deleted file mode 100644 index 17f168b..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Milestone 1 is Due on Monday Next Week.md.meta +++ /dev/null @@ -1,4 +0,0 @@ -section: 1 -tags: lab03 lab hidden -title: $:/Labs/03/Milestone 1 is Due on Monday Next Week -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Project Tasks.md b/tiddlers/content/labs/lab03/_Labs_03_Project Tasks.md deleted file mode 100644 index 685922e..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Project Tasks.md +++ /dev/null @@ -1,44 +0,0 @@ -1. At the moment the <> combobox on the `ProductEditor` dialog is only displaying some default values and does not contain the categories that have previously been entered into the system. - - * Add another method to the DAO class that returns all of the categories. Name the method `getCategories`. - - Add another `static` collection field to the DAO class for storing the categories. - - Modify the `saveProduct` method so that it also extracts the category from the product being saved (using the getter method to get the category from the product) and store it in the new field. - - Return the new field in the `getCategories` method. - - * Use a new `SimpleListModel` object to get the data into the category combobox on the `ProductEditor` dialog. It is the same process that you used to get the products into the product viewer dialog. - -1. Add a new DAO test to your existing test class to test that your new method returns categories correctly. - -1. Create the following two sequence diagrams using PlantUML. - - * A sequence diagram for the 'add a new product' use case. This diagram should show the flow of interactions from the user clicking the button on the menu, through to the created product object being stored via the product DAO. - - Don't forget to show the categories being loaded into the combo box. - - * A sequence diagram for the 'view all products' use case. It should show the flow of interactions from the user clicking the button on the menu, through to the dialog being displayed, and the products being loaded into the list. - - Create a new folder in the root of your project named <>. Save your `puml` files in this folder. - - You can use VS Code in the lab, or your own version (assuming you have the PlantUML plugin installed) to create the diagrams. If you have not taken INFO201 then refer to [lab 1](https://isgb.otago.ac.nz/infosci/INFO201/labs_release/raw/master/output/info201_labs.html#/Labs/Lab%2001/Software%20Installation:%5B%5B/Labs/Lab%2001/Software%20Installation%5D%5D%20%5B%5B/Labs/Lab%2001/Plugin%20Configuration%5D%5D) of INFO201 for instructions on installing and configuring VS Code and the PlantUML plugin. - - If you don't have VS Code installed then you may prefer to use one of the following online editors and copy and paste between the online editor and the file in your project (via a different text editor): - - * https://plantuml-editor.kkeisuke.com/ - * https://www.planttext.com/ - * https://sujoyu.github.io/plantuml-previewer/ - * http://www.plantuml.com/plantuml/ - - You were shown how to create sequence diagrams in INFO201. If you need a refresher or you have not taken INFO201 then there is a [sequence diagram review exercise](#/Review/Diagrams/Sequence%20Diagrams) that contains a quick tutorial. You can also look at lecture 13 from INFO201 (available on the INFO202 Blackboard under < Revision material > INFO 201">>). - - Make sure that your diagrams are committed pushed to GitBucket. You don't have to do anything special here --- just commit the project, and push as per usual. You should be able to see and view your diagrams via the GitBucket user interface. - -1. Don't forget to complete all four domain classes. The complete domain model including the methods, and relationships is part of milestone 1. - -## Bonus Tasks - -There is bonus task that is relevant to this lab: - -* Make the products appear in your `ProductViewer` dialog in sorted order (by product ID) when using the collections based DAO. This task is about using sorted collections in the DAO class as described in lecture 5. \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Project Tasks.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Project Tasks.md.meta deleted file mode 100644 index 6521c8f..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Project Tasks.md.meta +++ /dev/null @@ -1,4 +0,0 @@ -section: 7 -tags: lab03 lab hidden -title: $:/Labs/03/Project Tasks -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Redirect the Repository.md b/tiddlers/content/labs/lab03/_Labs_03_Redirect the Repository.md new file mode 100644 index 0000000..5a27c6c --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_Redirect the Repository.md @@ -0,0 +1,15 @@ +You cloned the project from our repository, so you won't be able to push any changes until you point the project at your own repository. + +1. Create a new repository on GitBucket named `lab03`. + +2. Copy the clone URL for the project (it starts with `https://` and ends with `.git`. + +3. In NetBeans, < Git > Repository > Open Configuration">>. This is the configuration file for the repository that is usually found in <>. + +4. Replace the current value of the `url` property with the URL that you copied. + +5. Save and close the file. + +6. Push the project. You should see that it appears in your GitBucket repository. + +You can now push changes to your own version of the repository --- it is completely disconnected from the original repository. diff --git a/tiddlers/content/labs/lab03/_Labs_03_Redirect the Repository.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Redirect the Repository.md.meta new file mode 100644 index 0000000..081bcda --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_Redirect the Repository.md.meta @@ -0,0 +1,4 @@ +section: 2.1 +tags: lab03 lab +title: /Labs/03/Redirect the Repository +type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Refactoring the DAO Dependencies.md b/tiddlers/content/labs/lab03/_Labs_03_Refactoring the DAO Dependencies.md new file mode 100644 index 0000000..5cdd871 --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_Refactoring the DAO Dependencies.md @@ -0,0 +1,50 @@ +The DAO fields are currently hard-coded to a specific DAO instance, which is being initialized in the dialog classes. If we want to switch from using one DAO to another we need to update the fields in all of our GUI classes. + +In this section we will refactor the system to allow us to pass the DAO objects into the dialogs rather that have the dialogs responsible for creating them. This is known as *inversion of control* --- the control of the dependency (the DAO objects in this case) is taken away from the user of the dependency (the dialogs) and is instead *injected* into the user via some mechanism (we will be passing the dependency to the dialogs via the constructor). + +Another benefit of *dependency injection* (which is what this specific form of *inversion of control* is called) is that it makes the system easier to test. We can now supply mock DAO objects to the GUI classes in order to test that the GUI classes are interacting with the DAO objects correctly. We will make use of this in the lab next week. + +We will refactor the system so that a single DAO object is created in the `App` class, and is passed through to the dialogs via the constructors. We need to pass it to the `MainMenu` frame, which will in turn pass it to the dialogs. + +1. Open the `StudentEditor` dialog. + +2. Locate the `dao` field. Note the following: + + * This field is using the `StudentDAO` interface type on the left hand side. This is important since we will be basing our mock DAO on the `StudentDAO` interface. + + * The field is `final`. This will help to ensure that the only object that is stored in this field is the one that will be passed into the constructor. Final fields can only be initialised at the point that they are declared, or via a constructor. + +3. Remove the field initialisation. Delete the right hand side of the declaration including the `=` character. + +4. Modify the constructor so that it takes an instance of the `StudentDAO` interface as a parameter. + + Use this parameter to initialise your DAO field. The initialisation should go before any code in the constructor that uses the DAO. + +5. You might notice some compiler errors appear in the other GUI classes --- we will fix those soon so ignore them for the meantime. + +6. Open the `MainMenu` frame. Add a `StudentDAO` field to the top of the class. Leave the field uninitialised. Make the field `private final` as done in the `StudentEditor`. + +7. Add a parameter to the `MainMenu` constructor just like you did in the `StudentEditor` dialog that initialises the DAO field. + +8. Fix the compiler error in the In the `btnAddActionPerformed` button handler by passing the new DAO field into the constructor call for the `StudentEditor` dialog. This is the handler that is called when the user clicks the <> button on the main menu. + +9. Open the `App` class. Fix the compiler error in this class by creating a DAO instance. It does not need to be a field --- just create a variable inside the `main` method: + + ```java + StudentDAO dao = new StudentCollectionsDAO(); + ``` +10. Pass the new `dao` instance into the `MainMenu` constructor. + +11. Complete the same process for the `StudentViewer` dialog. + +12. Fix any other errors relating to the DAO fields. You might need to move the initialisation of some fields into the constructor after the DAO field is initialised. + + You will also need to pass the DAO into the `StudentViewer` dialog when it is created in the `MainMenu`. + +13. Test the system by running it. You should see that it behaves as it used to. + +So what have we achieved with this refactoring? + +- There is now one place that we need to modify (the `App` class) if we want to change the type of DAO that is being used. Previously there were only two places, but that is only because our system is quite simple and only requires two dialogs. If there were ten dialogs there would be ten places that we would have needed to change. + +- We can now pass different types of DAO objects into our GUI classes for different purposes. For example, when we want to test the GUI classes we can pass *mock* DAO objects that can be used to verify that the GUIs are interacting with the DAO objects correctly. diff --git a/tiddlers/content/labs/lab03/_Labs_03_Refactoring the DAO Dependencies.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Refactoring the DAO Dependencies.md.meta new file mode 100644 index 0000000..fa88daa --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_Refactoring the DAO Dependencies.md.meta @@ -0,0 +1,4 @@ +section: 4.1 +tags: lab03 lab +title: /Labs/03/Refactoring the DAO Dependencies +type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Summary.md b/tiddlers/content/labs/lab03/_Labs_03_Summary.md new file mode 100644 index 0000000..40d70ba --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_Summary.md @@ -0,0 +1,10 @@ +That is the basics of testing. You now know: + +* How to drive tests using JUnit. +* How to evaluate tests using Hamcrest. +* How to drive and evaluate GUI tests using AssertJ Swing. +* How to isolate dependant components using Mockito. + +In Java land, JUnit and Hamcrest are the primary libraries that you will encounter. There are others, but those are the two big ones. AssertJ is the only library that we are aware of that can be used for testing Swing GUIs. Mockito is one of several mocking frameworks. Other languages have equivalents that behave in similar ways. + +We are not done with testing in {{$:/ou/parameters/Paper Code}} yet. We will show you how to test persistent DAOs (that store data in a database), and web application/services in future labs and lectures. However, the above list of topics are the main topics that you need to know about automated testing --- what remains will just be building on those topics. \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Summary.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Summary.md.meta new file mode 100644 index 0000000..6e56127 --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_Summary.md.meta @@ -0,0 +1,4 @@ +section: 4.5 +tags: lab03 lab +title: /Labs/03/Summary +type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Testing a Data Access Class.md b/tiddlers/content/labs/lab03/_Labs_03_Testing a Data Access Class.md new file mode 100644 index 0000000..f5fc44c --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_Testing a Data Access Class.md @@ -0,0 +1,37 @@ +Create tests for the `StudentCollectionsDAO` as shown in last week's lab. This is a fairly typical DAO class that is using collections to store the data that is similar to the DAO class that you created in INFO 201. + +1. Generate the test classes as shown in section <> of last week's lab. + + You will be using the `StudentCollectionsDAO` class rather than the `Calculator` class that is described in that section. + +2. Delete the generated constructor so that you won't be tempted to use it --- all initialisation should happen in the `setUp` method. + +3. Make all five tests fail by adding the following to each test method: + + ```java + fail("not implemented yet"); + ``` + +4. Show the test results pane using < IDE Tools > Test Results">>. + +5. Run the tests using < Test Project">>. Gradle will search the project for test methods and run them all. You can also test a single file as per usual by right clicking it in either the source editor or project pane and selecting <>. + + You should see that all five tests fail. + +6. Implement and test each test, one by one. Remove the `fail` call when you think you have finished a test. + + The `Invoice` test from section <> from last week's lab is similar to what is needed here --- swap `Invoice` for `StudentCollectionsDAO` and `InvoiceItem` for `Student` and you are most of the way there. + + Since the DAO collection is static you will need to use the `tearDown` method to remove all of the test students from the DAO (refer to section <> which covered this topic. + + Create three student objects in the `setUp`, but only save two of them in the DAO object. This gives you some data to test most of the methods with. The third student that has not been saved can be used to test the `save` method. + + All of your tests should pass when you are finished. + +7. Test your tests. Intentionally break the DAO methods, one by one --- for the `save` and `delete` methods you can comment out the line that adds/removes the student. For the `get` methods you can method you can return either an empty `ArrayList` or an empty `Student`. + + Your tests should fail --- if not then your tests are not sufficient. + +8. Undo the changes you made to break the tests, and run the tests again. They should pass again. + +9. Commit and push. diff --git a/tiddlers/content/labs/lab03/_Labs_03_Testing a Data Access Class.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Testing a Data Access Class.md.meta new file mode 100644 index 0000000..11a3c08 --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_Testing a Data Access Class.md.meta @@ -0,0 +1,4 @@ +section: 3 +tags: lab03 +title: /Labs/03/Testing a Data Access Class +type: text/x-markdown \ No newline at end of file diff --git "a/tiddlers/content/labs/lab03/_Labs_03_Testing the \047Search\047 Feature.md" "b/tiddlers/content/labs/lab03/_Labs_03_Testing the \047Search\047 Feature.md" new file mode 100644 index 0000000..559d18b --- /dev/null +++ "b/tiddlers/content/labs/lab03/_Labs_03_Testing the \047Search\047 Feature.md" @@ -0,0 +1,22 @@ +This test should check that the correct student is displayed when the user searches for a student via their student ID. + +You will need to stub the `getById` method since that is the method that the <> button calls. The stub code goes in the `setUp` method and looks like: + +```java +Student jack = new Student(1111, "Jack", "Chemistry"); +when(dao.getByID(1111)).thenReturn(jack); +``` + +This stub will only return the student `jack` when the ID `1111` is passed to the `getById` method. The purpose of these stub methods is to do provide the bare minimum functionality that allows the test to operate, using hard-coded data that can be checked in the test. + +The robot will need to enter the student's ID (use the ID that the `getById` stub expects) into the search box, and click the <> button. + +You can find the component names on lines 26--28 in the constructor for `StudentViewer`. + +Since the `getById` method should have been called when the button was clicked, the test should verify that this is the case and that the correct parameter was passed. The code for this looks like: + +```java +verify(dao).getById(1111); +``` + +The test should then check that the list is displaying the correct student. This code is similar to the code that you used in the previous test, except there will only be one student. diff --git "a/tiddlers/content/labs/lab03/_Labs_03_Testing the \047Search\047 Feature.md.meta" "b/tiddlers/content/labs/lab03/_Labs_03_Testing the \047Search\047 Feature.md.meta" new file mode 100644 index 0000000..2894859 --- /dev/null +++ "b/tiddlers/content/labs/lab03/_Labs_03_Testing the \047Search\047 Feature.md.meta" @@ -0,0 +1,4 @@ +section: 4.4 +tags: lab03 lab +title: /Labs/03/Testing the 'Search' Feature +type: text/x-markdown \ No newline at end of file diff --git "a/tiddlers/content/labs/lab03/_Labs_03_Testing the \047View Students\047 Feature.md" "b/tiddlers/content/labs/lab03/_Labs_03_Testing the \047View Students\047 Feature.md" new file mode 100644 index 0000000..5f5eb90 --- /dev/null +++ "b/tiddlers/content/labs/lab03/_Labs_03_Testing the \047View Students\047 Feature.md" @@ -0,0 +1,7 @@ +Using the `StudentEditorTest` as a guide, add code to the `testView` method in the `StudentViewerTest` class that tests that students in the DAO are being displayed in the dialog. + +The students should appear when the dialog is opened, so there is no need to instruct the robot to click anything for this test --- you just need to verify that the students are there. + +You will need to stub the `getAll` method in the mock in the `setUp` method so that it returns some student objects. This is similar to the stub for the `getMajors` method in the `StudentEditorTest`. + +Refer to the reference section <> for information on how to check what is being displayed in a `JList`. diff --git "a/tiddlers/content/labs/lab03/_Labs_03_Testing the \047View Students\047 Feature.md.meta" "b/tiddlers/content/labs/lab03/_Labs_03_Testing the \047View Students\047 Feature.md.meta" new file mode 100644 index 0000000..aecce20 --- /dev/null +++ "b/tiddlers/content/labs/lab03/_Labs_03_Testing the \047View Students\047 Feature.md.meta" @@ -0,0 +1,4 @@ +section: 4.3 +tags: lab03 lab +title: /Labs/03/Testing the 'View Students' Feature +type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Testing the Product Data Access Class.md b/tiddlers/content/labs/lab03/_Labs_03_Testing the Product Data Access Class.md deleted file mode 100644 index 48c30b5..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Testing the Product Data Access Class.md +++ /dev/null @@ -1,105 +0,0 @@ -[Lab 9](https://isgb.otago.ac.nz/infosci/INFO201/labs_release/raw/master/output/info201_labs.html#%2FLabs%2FLab%2009%2FLab%209%3A%20Testing%20in%20Java) in INFO201 was a fairly comprehensive overview of automated testing. Rather than go over all of that again, we will point you to the relevant bits of that lab. - -Those of you who have not taken INFO201 (and those of you who have forgotten how to do automated testing) should at least have a quick read through that lab --- automated testing is something that you should know about. - -1. Add an issue to GitBucket that describes that you need to create automated tests for the `ProductCollectionsDAO` class. - -1. We need to modify the build script to include the libraries for testing. It is time that we fixed up the outdated Gradle code that NetBeans generated when the project was created, so replace the entire contents of your `build.gradle` file with the following (delete everything in that file and replace it with the code below): - - ```gradle - plugins { - id 'application' - } - - repositories { - mavenCentral() - } - - dependencies { - def junitVer = '5.7.2' - testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junitVer - testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: junitVer - testImplementation group: 'org.hamcrest', name: 'hamcrest', version: '2.2' - } - - test { - useJUnitPlatform() - } - - run { - standardInput = System.in - } - - task openProjectFolder { - group = "Directories" - description = "Open the project root in the system file manager." - doFirst { - println('Opening: ' + file(projectDir)) - java.awt.Desktop.getDesktop().open(file(projectDir)); - } - } - - def ignored=""" - .gradle - .classpath - .project - build - bin - dist - *.zip - *.tgz - *.class - .DS_Store - """ - - task createGitIgnore { - group = "Git" - description = "Create the project's .gitignore file." - doLast { - def file = new File(projectDir, ".gitignore") - if ( !file.exists() ) { - println('Creating .gitignore') - file.text = ignored - } else { - println('.gitignore already exists') - } - } - } - - - mainClassName = 'Main' - ```` - -1. Save the `build.gradle` file and rebuild the project using < Build">>. You should see Gradle downloading the necessary libraries by clicking the <> notification at the bottom right of the NetBeans status bar. You will need to wait for that process to complete --- there aren't many libraries so it should be fairly quick. - -1. Generate the test classes as shown in section [2.3](https://isgb.otago.ac.nz/infosci/INFO201/labs_release/raw/master/output/info201_labs.html#%2FLabs%2FLab%2009%2FCreate%20the%20test%20class) of INFO201, lab 9. - - You will be using your DAO class rather than the `Calculator` class that is described in that section. - -1. Delete the generated constructor so that you won't be tempted to use it --- all initialisation should happen in the `setUp` method. - -1. Make all three tests fail by adding `fail();` to each test method. - -1. Show the test results pane using < IDE Tools > Test Results">>. - -1. Run the tests using < Test Project">>. Gradle will search the project for test methods and run them all. You can also test a single file as per usual by right clicking it in either the source editor or project pane and selecting <>. - - You should see that all three tests fail. - -1. Implement and test each test, one by one. Remove the `fail` call when you think you have finished a test. Section [3](https://isgb.otago.ac.nz/infosci/INFO201/labs_release/raw/master/output/info201_labs.html#%2FLabs%2FLab%2009%2FMore%20comprehensive%20example:%5B%5B%2FLabs%2FLab%2009%2FMore%20comprehensive%20example%5D%5D%20%5B%5B%2FLabs%2FLab%2009%2FTesting%20Invoice%5D%5D%20%5B%5B%2FLabs%2FLab%2009%2FTesting%20with%20persistent%20data%5D%5D) of the INFO201 lab has a fairly similar example --- swap `Invoice` for `ProductCollectionsDAO` and `InvoiceItem` for `Product` and you are most of the way there. - - Since the DAO collection is static you will need to use the `tearDown` method to remove all of the test products from the DAO (refer to section [3.3.2.1](https://isgb.otago.ac.nz/infosci/INFO201/labs_release/raw/master/output/info201_labs.html#%2FLabs%2FLab%2009%2FTesting%20with%20persistent%20data) of INFO201 lab 9 for an explanation). - - Create three products in the `setUp`, but only save two of them in the DAO object. This gives you some data to test the `removeProduct` and `getProducts` methods with. The third product that has not been saved can be used to test your `saveProduct` method. - - The code in the test methods from INFO201 lab 9 has everything that you need to test your DAO methods. - - All of your tests should pass when you are finished. - -1. Test your tests. Intentionally break your DAO methods --- for the `saveProduct` and `removeProduct` methods you can comment out the line that adds/removes the product. For the `getProducts` method you can return an empty `ArrayList`. - - Your tests should fail --- if not then your tests are not sufficient. The `removeProduct` test might trick you here. If you don't first check that the product you are about to delete exists in the DAO, then you can't actually be sure that the `removeProduct` method removed anything. - -1. Undo the changes you made to break the tests, and run the tests again. They should pass again. - -1. Commit and close the issue. \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Testing the Product Data Access Class.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Testing the Product Data Access Class.md.meta deleted file mode 100644 index 84c5723..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Testing the Product Data Access Class.md.meta +++ /dev/null @@ -1,4 +0,0 @@ -section: 5.1 -tags: lab03 hidden -title: $:/Labs/03/Testing the Product Data Access Class -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_The Product Data Access Class.md b/tiddlers/content/labs/lab03/_Labs_03_The Product Data Access Class.md deleted file mode 100644 index 56a44ec..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_The Product Data Access Class.md +++ /dev/null @@ -1,49 +0,0 @@ -We need somewhere to store the product objects that the product editor dialog creates. - -The best way to do this is to encapsulate the storage into a separate class. If we do this properly then we will be able to easily change the storage mechanism at a later date (such as switching from collections to a database) without affecting the GUIs. - -We will create a data access class for managing the storage of the product objects. - -The industry refers to instances of these classes as Data Access Objects (DAO). You can read more about the DAO concept at: - -[http://en.wikipedia.org/wiki/Data_access_object](http://en.wikipedia.org/wiki/Data_access_object) - -One of the problems that object-oriented languages have is that you often find that the place that a piece of data is stored is five times removed from the location that needs it. DAO classes help us with this problem because they give us a centralised location that all objects can use to access the data. - -1. Add an issue to GitBucket that describes that you need to create a data access class for handling the storage of the products. - -1. Create a class in the `dao` package. Name the class `ProductCollectionsDAO` since it is a DAO class that will store products using collections. - -1. We need a place to store the product objects. The quickest way to do this is to use a `private`, `static`, `ArrayList` field. The field will hold the products, so name it appropriately (use a plural to indicate that the field holds many products). - - Don't forget to initialise the field (unless you enjoy debugging null-pointer exceptions). - - Take a second to think about why the field needs to be `static`. - -1. The class will need the following methods: - - * A method for saving a product. It will take a single product as a parameter and add it to the `ArrayList`. This method does not need to return anything. Name this method `saveProduct`. - - * A method for getting all of the products. It will take no parameters and will return the entire `ArrayList`. Name this method `getProducts`. - - * A method for removing a product. It will take a single product as a parameter and remove it from the `ArrayList`. This method does not need to return anything. Name this method `removeProduct`. - -1. Did you remember to 'program to an interface'? - - You should be using `Collection` on the left hand side of the field/method declarations instead of `ArrayList`. - - If not, fix it now. It should look like: - - ```java - private static Collection products = new ArrayList<>(); - ``` - - The `getProducts` method should also be using `Collection` as the return type. - -1. Did you remember to specify the 'type' of the collections? - - You should be using the angle bracket notation (as shown in the examples in the previous step) to specify what type of objects your collections are expecting to hold. - - If not, fix it now. - -1. Commit. This class is now complete, so you can use the `Closes #4` command in your commit message to close the issue (assuming the relevant issue is #4 --- adapt to suit). \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_The Product Data Access Class.md.meta b/tiddlers/content/labs/lab03/_Labs_03_The Product Data Access Class.md.meta deleted file mode 100644 index 56cdb85..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_The Product Data Access Class.md.meta +++ /dev/null @@ -1,4 +0,0 @@ -section: 5 -tags: lab03 hidden -title: $:/Labs/03/The Product Data Access Class -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_The Product Viewer Dialog.md b/tiddlers/content/labs/lab03/_Labs_03_The Product Viewer Dialog.md deleted file mode 100644 index 5c92ad2..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_The Product Viewer Dialog.md +++ /dev/null @@ -1,23 +0,0 @@ -We need a dialog that allows a user to view the products that have been entered into the system. Take a quick look at the mock-up of this dialog in the product specification document (section [4.1.2.3](https://isgb.otago.ac.nz/info202/shared/project/raw/master/output/info202_project.html#%2FMilestones%201%20%26%202%2FViewing%20Products)) so that you know what you are aiming for. - -1. Add a new issue to GitBucket. We are about to start work on the dialog that allows the user to view the products, so name/describe the issue appropriately. - -1. Create a new `JDialog` in the `gui` package named `ProductViewer`. - -1. Add a *Scroll Pane* from the *Swing Containers* palette to the form. It should take up most of the form leaving a little bit at the top for the search and filter components, and a little bit of room at the bottom for then buttons. You can resize this later once you have added the other components. - -1. Add a *List* (`JList`) component to the scroll pane. A *JList* component is able to display a collection of objects and allow the user to select one. It is similar to a combobox but is expanded by default whereas a user needs to click the drop-down button to expand a combobox. - -1. Add a button for closing the dialog and set the variable name and text of the button to appropriate values. Make sure it is attached to one of the dialog's bottom snap boundaries. - -1. Resize the scroll pane so it snaps to the top of the button. This will make the scroll pane and list resize vertically when the form is resized. You should make sure that the scroll pane will also resize horizontally. - -1. Add a button click handler to the *close* button that closes the form by calling `dispose()`. - -1. Now you can add a button handler to the <> button in the `MainMenu` frame that will display the `ProductViewer` dialog. - -1. Test your modification to the main menu by running the application. - -1. Now is a good time to commit. We haven't finished with this class, so don't close the issue just yet. This is the last time that we will tell you to commit. From now on you should use your own judgement on when to commit and create issues. Remember to reference the associated issue --- if you are doing things correctly then pretty much every commit should reference a corresponding issue. - - Try to get into the habit of using the issues list on GitBucket as your to-do list for the project. \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_The Product Viewer Dialog.md.meta b/tiddlers/content/labs/lab03/_Labs_03_The Product Viewer Dialog.md.meta deleted file mode 100644 index fab982e..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_The Product Viewer Dialog.md.meta +++ /dev/null @@ -1,4 +0,0 @@ -section: 6 -tags: lab03 hidden -title: $:/Labs/03/The Product Viewer Dialog -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_The Student System.md b/tiddlers/content/labs/lab03/_Labs_03_The Student System.md new file mode 100644 index 0000000..edf6e7a --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_The Student System.md @@ -0,0 +1,17 @@ +We will give you a starting project for this week's lab. It is a modified version of the student system that you have seen in recent lectures. It is very similar to what you worked on in the final milestone of the e-tail system in INFO 201 (for those of you who took INFO 201). + +This project is available on GitBucket at: + +https://isgb.otago.ac.nz/info202/shared/student-system + +1. Visit the above page in a web browser. + +2. Clone the project (< Remote > Clone">> in NetBeans). Make sure that you do not store it inside any other repository folders since bad things happen if you nest Git repositories. A logical place to store this repository is in the root of the <> folder that we asked you to create last week. + +3. Open the project in NetBeans (NetBeans will probably offer to open it for you as part of the clone process). + +4. Ignore any warning dialogs relating to "project problems", and build the project to force Gradle to download the libraries for the project (< Build">>). + +5. Run the project and play with it a bit to work out what features it has. This system has some extra bells and whistles that we didn't ask you to implement in INFO 201, but otherwise should look very similar to what you created in the final milestone of the e-tail system. + +<> There will be some errors in the test packages. This is because the tests won't work until we complete the refactoring that was mentioned earlier --- you can still run the project despite the errors. diff --git a/tiddlers/content/labs/lab03/_Labs_03_The Student System.md.meta b/tiddlers/content/labs/lab03/_Labs_03_The Student System.md.meta new file mode 100644 index 0000000..6afa8e3 --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_The Student System.md.meta @@ -0,0 +1,4 @@ +section: 2 +tags: lab03 lab +title: /Labs/03/The Student System +type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_User Interface Testing.md b/tiddlers/content/labs/lab03/_Labs_03_User Interface Testing.md new file mode 100644 index 0000000..095b042 --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_User Interface Testing.md @@ -0,0 +1,33 @@ +Testing user interface code is difficult. The input components and handler methods are usually all `private` meaning your testing code can not access them. The result of executing the handlers is also often not reflected in the user interface --- the changes triggered by the user will often happen in the data store. + +To do this properly, we need the tests to: + +* Enter data into the input components (text fields, combo boxes, etc.) on the forms. + +* Execute the click handlers for the relevant buttons/components. + +* Test that the handler did what it was supposed to. This will probably involve checking that the data was correctly modified via the appropriate DAO. + +* Check that the components on the form are displaying the correct details in response to our actions. + +Take a few seconds to consider how you could do this. You could make significant changes to the user interface to make everything `public` --- that might be enough to allow you to get the job done. However this breaks some of the rules of encapsulation. Doing this would be the opposite of refactoring --- making the code worse (occasionally/euphemistically called *refuctoring*). + +If you have not encountered the term *refactoring* before, it refers to restructuring the code for the sole purpose of increasing the quality of the code without modifying the behaviour of the code. Often the refactoring is about adding abstractions that make the code easier to work with, and easier to test. + +Luckily for us there are several libraries that can help us with this. + +We will use a framework called *AssertJ* (https://assertj.github.io/doc/) that allows us to interact with and test Swing GUIs. AssertJ offers similar functionality to Hamcrest --- it provides mechanisms for verifying the state of a system that can be used in automated tests. AssertJ also has a module specifically for working with Swing user interfaces. + +The AssertJ Swing module is specifically for testing Swing user interfaces. For web systems, there is a tool called *Selenium* that can interact with web based user interfaces is much the same way. Most AJAX libraries also provide their own equivalent of AssertJ Swing for testing user interfaces that have been created using that library. Basically, there will generally be some equivalent to AssertJ Swing for whatever user interface toolkit you are working with. + +AssertJ helps us with interacting with the GUI, but given that most GUI operations involve a DAO, how do we ensure that the DAO is being used correctly? We already have a set of tests that test the DAO, so doing this again via the GUI is a bit pointless. + +We could create a modified DAO that is specifically for testing purposes. It could tell our testing code which DAO methods have been called and what was passed into them. + +But we have to create a new DAO from scratch for testing right? Nope. This is what *mocking* frameworks are all about. They allow us to quickly knock up mock objects for testing purposes. We will be using a framework call Mockito (http://mockito.org/) for mocking our DAO. + +We will need to refactor the system to allow the DAO objects to be *injected* into the dialog classes so that we have a way of controlling which DAO objects are being used --- when testing we will be using mock DAO objects. Using a mock DAO will allow us to: + +* Isolate the GUI classes from the DAO classes. We are now testing the GUI classes in isolation since they will no longer be using a real DAO class that may contain its own bugs which might affect the GUI testing. + +* Use the mock to verify that the GUI is interacting with the DAO correctly. We can ask the mock if a particular DAO method has been called, and then verify that the parameters passed to that method were what we were expecting. diff --git a/tiddlers/content/labs/lab03/_Labs_03_User Interface Testing.md.meta b/tiddlers/content/labs/lab03/_Labs_03_User Interface Testing.md.meta new file mode 100644 index 0000000..6b71cf5 --- /dev/null +++ b/tiddlers/content/labs/lab03/_Labs_03_User Interface Testing.md.meta @@ -0,0 +1,4 @@ +section: 4 +tags: lab03 lab +title: /Labs/03/User Interface Testing +type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Using the Product Data Access.md b/tiddlers/content/labs/lab03/_Labs_03_Using the Product Data Access.md deleted file mode 100644 index 6b61221..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Using the Product Data Access.md +++ /dev/null @@ -1,15 +0,0 @@ -Open your `ProductEditor` dialog and switch to the source code using the the <> button in the bar the top of the file. - -1. Add a field to the dialog that is an instance of the DAO class. Don't forget to initialise the field. - -1. Modify the save button click handler in the dialog so that it uses the DAO field to save the product that is being created by calling the `saveProduct` method on the DAO instance. - -1. Add a `dispose` call after saving the product. Users are used to seeing a window close when they are finished entering data into it. - -1. Test the system by running it. Add a new product. You won't see much happen at this point, but at least the system shouldn't crash when you click the <> button. - -1. Now would be a good time to commit and close the issue since you have completed the 'add a new product' feature. - - Generally, you should close issues when you are think that you are finished with them. This allows you to treat the issues view on GitBucket as a 'to do' list. You can always reopen an issue at a later date if you need to. - -**A note on error handling**: We do not expect you to make this dialog bullet-proof at this point. If the user enters invalid data (or no data) then the system will likely throw an error --- that is OK. There will be a later lab that covers input validation and exception handling where we show you how to make the dialog resilient to user errors. \ No newline at end of file diff --git a/tiddlers/content/labs/lab03/_Labs_03_Using the Product Data Access.md.meta b/tiddlers/content/labs/lab03/_Labs_03_Using the Product Data Access.md.meta deleted file mode 100644 index 0e8db82..0000000 --- a/tiddlers/content/labs/lab03/_Labs_03_Using the Product Data Access.md.meta +++ /dev/null @@ -1,4 +0,0 @@ -section: 5.2 -tags: lab03 hidden -title: $:/Labs/03/Using the Product Data Access -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/reference/Gradle/_Reference_Gradle_build.gradle.md b/tiddlers/content/reference/Gradle/_Reference_Gradle_build.gradle.md index 7b16d5a..b5ae72a 100644 --- a/tiddlers/content/reference/Gradle/_Reference_Gradle_build.gradle.md +++ b/tiddlers/content/reference/Gradle/_Reference_Gradle_build.gradle.md @@ -94,7 +94,7 @@ doLast { def file = new File(projectDir, ".gitignore"); if ( !file.exists() ) { - println('Creating .gitignore'); + println("Creating .gitignore"); gitIgnored.lines().each { f -> if(!f.trim().isBlank()) { @@ -103,7 +103,7 @@ } } else { - println('.gitignore already exists'); + println(".gitignore already exists"); } } } diff --git "a/tiddlers/content/reference/Testing/_Reference_Testing_GUI Testing_Checking the Contents of a List Component \050JComboBox, JList\051.md" "b/tiddlers/content/reference/Testing/_Reference_Testing_GUI Testing_Checking the Contents of a List Component \050JComboBox, JList\051.md" deleted file mode 100644 index 045ee2a..0000000 --- "a/tiddlers/content/reference/Testing/_Reference_Testing_GUI Testing_Checking the Contents of a List Component \050JComboBox, JList\051.md" +++ /dev/null @@ -1,18 +0,0 @@ -Sometimes you will need to check the contents of a list component (such as a `JList` or `JComboBox`). An example would be making sure that the report dialog is displaying the correct products in response to clicking the *search* button or *category filter* combobox. - -You can check that the component contains the correct number of elements using: - -```java -// products JList should contain 2 products -fixture.list("lstProducts:").requireItemCount(2); -``` - -To check for specific elements in the list component, you need to look at the component's model. You can use any of the usual Hamcrest collection matchers to check the model for specific elements. - -```java -// get the model -SimpleListModel model = (SimpleListModel) fixture.list("lstProducts").target().getModel(); - -// check the contents -assertThat(model, containsInAnyOrder(product1, product2, product3)); -``` \ No newline at end of file diff --git "a/tiddlers/content/reference/Testing/_Reference_Testing_GUI Testing_Checking the Contents of a List Component \050JComboBox, JList\051.md.meta" "b/tiddlers/content/reference/Testing/_Reference_Testing_GUI Testing_Checking the Contents of a List Component \050JComboBox, JList\051.md.meta" deleted file mode 100644 index 2606c2c..0000000 --- "a/tiddlers/content/reference/Testing/_Reference_Testing_GUI Testing_Checking the Contents of a List Component \050JComboBox, JList\051.md.meta" +++ /dev/null @@ -1,3 +0,0 @@ -tags: hidden -title: $:/Reference/Testing/GUI Testing/Checking the Contents of a List Component (JComboBox, JList) -type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/reference/Testing/_Reference_Testing_GUI Testing_Checking the Contents of a List Component.md b/tiddlers/content/reference/Testing/_Reference_Testing_GUI Testing_Checking the Contents of a List Component.md new file mode 100644 index 0000000..ca44485 --- /dev/null +++ b/tiddlers/content/reference/Testing/_Reference_Testing_GUI Testing_Checking the Contents of a List Component.md @@ -0,0 +1,18 @@ +Sometimes you will need to check the contents of a list component (such as a `JList` or `JComboBox`). An example would be making sure that the report dialog is displaying the correct items. + +You can check that the component contains the correct number of elements using: + +```java +// products JList should contain 2 products +fixture.list("lstProducts:").requireItemCount(2); +``` + +To check for specific elements in the list component, you need to look at the component's model. You can use any of the usual Hamcrest collection matchers to check the model for specific elements. + +```java +// get the model +SimpleListModel model = (SimpleListModel) fixture.list("lstProducts").target().getModel(); + +// check the contents +assertThat(model, containsInAnyOrder(product1, product2, product3)); +``` \ No newline at end of file diff --git a/tiddlers/content/reference/Testing/_Reference_Testing_GUI Testing_Checking the Contents of a List Component.md.meta b/tiddlers/content/reference/Testing/_Reference_Testing_GUI Testing_Checking the Contents of a List Component.md.meta new file mode 100644 index 0000000..494f490 --- /dev/null +++ b/tiddlers/content/reference/Testing/_Reference_Testing_GUI Testing_Checking the Contents of a List Component.md.meta @@ -0,0 +1,3 @@ +tags: reference +title: /Reference/Testing/GUI Testing/Checking the Contents of a List Component +type: text/x-markdown \ No newline at end of file diff --git a/tiddlers/content/review/java_exercises/_Review_Java Exercises_Create a Sequence Diagram.md b/tiddlers/content/review/java_exercises/_Review_Java Exercises_Create a Sequence Diagram.md index 7642c4b..404f86d 100644 --- a/tiddlers/content/review/java_exercises/_Review_Java Exercises_Create a Sequence Diagram.md +++ b/tiddlers/content/review/java_exercises/_Review_Java Exercises_Create a Sequence Diagram.md @@ -2,6 +2,6 @@ Draw a sequence diagram of the 'search' feature of your contact list system. Start with the user selecting the 'Search' option from the menu. -Refer to the [sequence diagrams review exercise](#/Review/Diagrams/Sequence%20Diagrams) if you have not taken INFO201, or you need a quick refresher. +Refer to the <> if you have not taken INFO201, or you need a quick refresher.
txtId
txtName
cmbMajor
btnSave
StudentEditor
setName