Thursday, April 4, 2013

Unknown’s Unidentified – Implicit Requirements

"Why this case was not covered in your test plan? Have not you done test coverage sign off? Probably you should take our organization process training (so called) to extemporize your analytic skills! From henceforth work with “Mr. Smart” (most likely pet of manager) to certain no false-steps are seen in future."

Ever faced whichever of these questions in your testing life path, Well I have faced a few, to be straightforward. The moment these queries hit our cochlea, stimulus ensures to point our finger towards business analyst or project manager, to outline all requirements. Yes, you are right but it is also the liability of a blameless tester to serve his stakeholder, better

There could be voluminous technical or non-technical documents spawned in a project, but it is predominantly the tester artifacts which catch customer’s responsiveness. Because each tester’s artifact reveals readiness & quality of the project/product, which customers want to utilize & of course pay for, correspondingly. So why can’t testers utilize this prospect to retain customers in page with project’s status.

Let’s start with Test Plan attributes
  • Scope - Defining scope is vital part of planning. I have seen test plans where scope is defined within 500 characters!. Make sure to present the range of testing, unmistakably.
  • What won’t be tested? - Identify boundaries and potential environment variables. Call out which will NOT be covered in your test execution. This section will bring out hidden requirements from any dependent team or even customers.

  • Assumptions – Whenever you author any shared document, explicitly insist on assumptions you did while drafting that doc. Having said that do not quote negative cases or uncertain conceptions under assumption section. Ensure this section is precise and informative.
    • Scenario: Let’s say you are validating “Font Styles” for Microsoft Word
    • Valid: Font style is supported for both Horizontal and Vertical<Japanese> Contents
    • Invalid: Font style is not applicable for superscript and subscript.[Negative case]
    • Invalid: Font style rendering are respected only for ASCII and UTF-8 encoded formats.[Uncertain about encoding formats, this can be added as an open question]
  • Unanswered Questions/ Open items - Here capture all confusions lingering in your mind. You can even append the point of contact for each item, for better tracking.
    Test Case Categorization - Use either breadth <user story> or depth <Feature/Component> wise approach to tag test cases. Remember each has their own pros and cons, so stick to one that fits you. Gaps can be spotted in ease if suitable test case classification is in place, by any reviewer.

    Test Data - Numerous software failures arise due to improper handling of data, misleading information and unexpected inputs. If possible get data from customer field or ensure to share format of likely inputs with real time users/stakeholders. Real time data are often unpredictable!

    Test Result - Test results should be logically complete, quantifiable and measurable. In short, any stakeholder should visualize quality from our test results. Recently I stumbled upon a test result document from a start-up organization, which had user stories and its corresponding status (Pass or Fail), making it more informative.

    Reviews - Voluminous after-effects arise due to the mis-communication or synchronization among project stakeholders. So review all your artifacts with possible stakeholders. Try to involve actual customer once in a while. Reviews will elude dis-satisfiers, who forgot to explicitly mention about a requirement or assumed it as a basic provision in equivalent application. Reviews also aids in avoidance of non-delighted stakeholders, who may not be aware of actual technology, standards or domain updates

    Questioning is a strategic skill for any passionate tester so do cultivate it. Before closing any artifact, ask yourself “Have I asked questions”? This will encourage in perceiving unknown/hidden requirements. As always, want to share your comments?? Please feel free. 

    Tuesday, March 19, 2013

    Swing Application - Searches DB & display results through JTable in JTabbedPane

    This feed narrates how to search for a record in a JTabbedPane. The search results are displayed in tabular form using JTable. To download these java files, please click on corresponding filename. Lets drill down, to the code.
    • OrderView - Main class, which calls out layout design. (i.e UI)
    • ItemTabelModel - An abstract table model, to display search results in tabular form
    • OrderDAO - Takes care of DB interaction, I have used MySQL
    • OrderInfo - A class to demonstrate order object
    OrderView.java
    • Creates JTabbedPane with four panels - Create, Edit, Delete & Search
    • Searches for record in DB using OrderDAO class
    • Search is invoked by "Enter" key as well as "Search" button
    • Zero & Empty search results are handled
    • Search result-set size need not be one.
    • Implements listeners for KeyTyped, KeyPressed and KeyReleased events
    • Display search results in tabular form using JTable
    • Snippet shared here is confined to "Search" tab, other tabs are not designed

      public class OrderView implements ActionListener {

    ArrayList orderList;
    OrderDAO oDAO; <- For DB interaction
    JFrame appFrame;
        JLabel jlbName, jlbItem;
        JTextField jtfName,jtfDate;
        JTabbedPane appPane;
        JButton jbbSave, jbnDelete, jbnClear, jbnUpdate, jbnSearch;
        JTable jtbOrder;
        JScrollPane sp;
        JPanel jPaneCreate,jPaneEdit,jPaneDelete,jPaneSearch;
       
        String name, address, email;
        int recordNumber;
        String nameStr;   
        private ItemTableModel ItemTabModel;
       
        public static void main(String args[]){
            new OrderView(); 
         }
        
        public OrderView()
        {       
          createGUI();    
          orderList = new ArrayList();
          oDAO=new OrderDAO();
        }
        
        public void createGUI(){

        /*Create a frame, get its contentpane and set layout*/
        appFrame = new JFrame("View your order status");
        appPane=new JTabbedPane();
        jPaneCreate=new JPanel(new GridLayout(5,2));
        jPaneEdit=new JPanel(new GridLayout(5,2));
        jPaneDelete=new JPanel(new GridLayout(5,2));
        jPaneSearch=new JPanel(new GridLayout(5,2));   
       
        appPane.setTabPlacement(JTabbedPane.LEFT);   
        appFrame.getContentPane().add(appPane);
        appPane.add("Create New",jPaneCreate);
        appPane.add("Edit/Update",jPaneEdit);
        appPane.add("Delete",jPaneDelete);
        appPane.add("Search",jPaneSearch);
       
        //set shortcuts for each tab
          appPane.setMnemonicAt(0 , KeyEvent.VK_C);
        appPane.setMnemonicAt(1 , KeyEvent.VK_E);
        appPane.setMnemonicAt(2 , KeyEvent.VK_D);
        appPane.setMnemonicAt(3 , KeyEvent.VK_S);   
        //Arrange components on contentPane and set Action Listeners to each JButton
        arrangeComponentsCreate();
         arrangeComponentsEdit();
        arrangeComponentsDelete();
        arrangeComponentsSearch(); 
               
        appFrame.pack();
        appFrame.setVisible(true);
        appFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
       
        private void arrangeComponentsSearch() {
         jlbName = new JLabel("Customer Name");
         jlbItem = new JLabel("Item Ordered");  
         jtfName=new JTextField(20);
         jtfDate=new JTextField(20);
         //listeners ensure typed search strings are converted to uppercase, as & when key typed
         jtfName.addKeyListener(new KeyAdapter(){
         public void keyReleased(KeyEvent e) {
                    JTextField textField = (JTextField) e.getSource();
                    String text = textField.getText();
                    textField.setText(text.toUpperCase());
                }

                public void keyTyped(KeyEvent e) {
                    // TODO: Do something for the keyTyped event
                 JTextField textField = (JTextField) e.getSource();
                    String text = textField.getText();
                    textField.setText(text.toUpperCase());
                }
              //Invoke search person on "Enter" button event
                public void keyPressed(KeyEvent e) {
                    // TODO: Do something for the keyPressed event
                 JTextField textField = (JTextField) e.getSource();
                    String text = textField.getText();
                    textField.setText(text.toUpperCase());
                    if (e.getKeyCode()== KeyEvent.VK_ENTER )
                    {
                     searchPerson();
                    }
                }
         });
        
           GridBagConstraints c = new GridBagConstraints();
            setMyConstraints(c,0,0,GridBagConstraints.CENTER);
            jPaneSearch.add(getFieldPanel(),c);
            setMyConstraints(c,0,1,GridBagConstraints.CENTER);
            jPaneSearch.add(getButtonPanelSearch(),c);         
            jtbOrder=new JTable();
    ItemTabModel=new ItemTableModel();
    jtbOrder.setModel(ItemTabModel); 
     sp=new JScrollPane(jtbOrder); 
            jbnSearch.addActionListener(this);
    }  
        
        public void actionPerformed (ActionEvent e){  
         if (e.getSource() == jbnSearch)
          searchPerson();//clicking search button should invoke searchPerson() function   
        }

    private JPanel getButtonPanelSearch() {
    //Search Button
    JPanel p = new JPanel(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        setMyConstraints(c,0,0,GridBagConstraints.CENTER);
         p.add(jbnSearch,c);
    return p;
    }

         private JPanel getFieldPanel() {
           JPanel p = new JPanel(new GridBagLayout());
           p.setBorder(BorderFactory.createTitledBorder("Details"));
           GridBagConstraints c = new GridBagConstraints();
           setMyConstraints(c,0,0,GridBagConstraints.EAST);
           p.add(jlbName,c);
           setMyConstraints(c,1,0,GridBagConstraints.WEST);
           p.add(jtfName,c);
           setMyConstraints(c,0,1,GridBagConstraints.EAST);
           p.add(jlbItem,c);
           setMyConstraints(c,1,1,GridBagConstraints.WEST);
           p.add(jtfDate,c);
           return p;
         }

        private static void setMyConstraints(GridBagConstraints c, 
               int gridx, int gridy, int anchor) {
               c.gridx = gridx;//manages the layout of controls
               c.gridy = gridy;
               c.anchor = anchor;
            }
        
    public void searchPerson() {        
         name = jtfName.getText();    
        /*clear contents of arraylist if there are any from previous search*/    
        orderList.clear();
        recordNumber = 0;

        if(name.equals("")){
        JOptionPane.showMessageDialog(null,"Please enter person name to search.");
                             //when a empty string is searched
        clear();
        }
        else{
        /*get an array list of searched persons using PersonDAO*/
        orderList = oDAO.searchPerson(name);
        if(orderList.size() == 0){
        JOptionPane.showMessageDialog(null, "No records found.");
        //Perform a clear if no records are found.-Refer screenshot
        clear();
        }
        else
        {    
        //Erasing previous history
        recordNumber=orderList.size();
        ItemTabModel.removeall();
        jPaneSearch.remove(jtbOrder);
        jPaneSearch.remove(sp);
        jPaneSearch.repaint();    
        //If there are more search results, display all in tabular form
        while(recordNumber>0)
        {
        /*downcast the object from array list to OrderInfo*/
        OrderInfo person = (OrderInfo) orderList.get(recordNumber-1); 
                      ItemTabModel.addOrderInfo(person);
                       recordNumber--;
        }    
        //Redraws the table
        jPaneSearch.add(sp);
        jPaneSearch.revalidate();   
        }    
        clear();        
        }
    }
    private void clear() {
    //Clears the textbox and sets focus
    jtfName.setText("");
    jtfName.requestFocusInWindow();
    }
     }

    Here are the snapshots of OrderView Application
    Search Results Zero Results Empty Search string
    Search Results Empty search string Zero search results
    I have not briefed other java files since they are trivial in function. Modify these code to your needs and let me know if you face any errors. To note, ensure you have MySQL connector jar in java build path to access database. Kindly share your comments, if any