简体   繁体   中英

Writing test case for Junit testing

As a developer, I'm a newbie to Unit testing and have a requirement to write a test case to unit test the following code. Could somebody help me here and also give me some pointers on how to write unit tests in eclipse.

private void handle(final DocumentEvent e) { 
    Document doc = e.getDocument(); 
    try { 
       String text = e.getDocument().getText(0, doc.getLength()); 

       if (text.length() >= maxMessageSize) { 
            try { 
               component.getHighlighter()
                        .addHighlight(maxMessageSize, text.length() + 1, painter); 
            } catch (BadLocationException ex) { 
               System.out.println(ex.getMessage()); 
            } 
       } else { 
            component.getHighlighter().removeAllHighlights(); 
       } 
    } catch (BadLocationException e1) { 
       System.out.println(e1.getMessage()); 
    } 
} 

Thanks


Update

For some reason when I running the test case, I'm not getting any coverage at all. Am I doing something wrong here?? Further researching suggests that I need to use test.perform() method to call the method I want to test.. Is that correct?? Can you please suggest something?? Here is the code:

public class TestMaxLength {
  static final int maxMessageSize = 125;
  JTextPane textPane = new JTextPane();
  //***EasyMock varibles****
  private JTextComponent mockComponent;
  private MaxLength classUnderTest;
  private DocumentEvent mockEvent;
  private Document mockDocument;
  private Highlighter mockHighlighter;

  @Before public void setUp() {
    mockComponent = EasyMock.createMock(JTextComponent.class);
    mockEvent = EasyMock.createMock(DocumentEvent.class); 
    mockDocument = EasyMock.createMock(Document.class); 
    EasyMock.expect(mockEvent.getDocument()).andStubReturn(mockDocument);
    EasyMock.expect(mockDocument.getLength()).andReturn(256); 
    mockHighlighter = EasyMock.createMock(Highlighter.class); 
    EasyMock.expect(mockComponent.getHighlighter()).andReturn(mockHighlighter);
  }

  @Test public void testSetLength() { 
    MaxLength maxListener = new MaxLength(125); 
    maxListener.decorate(textPane);
  }

  @Test 
  public void testEmptyText() { 
    EasyMock.expect(mockDocument.getText(0, 1)).andStubReturn(""); 
    mockHighlighter.removeAllHighlights(); 
    EasyMock.replay(mockComponent, mockEvent, mockDocument, mockHighlighter);      
    classUnderTest.handle(mockEvent);      
    EasyMock.verify(mockComponent, mockEvent, mockDocument, mockHighlighter); 
  }     
}

The decorate(JtextComponent jComponent) method is present in the class to be tested ( MaxLength ) and is defined as :

public final void decorate(final JTextComponent c) {
  //TODO throw exception if already decorating
  this.component = c;
  component.getDocument().addDocumentListener(this);
}
#

UPDATE:

@Peter: Managed to find out that it is not the Component class that is the problem but instead I needed asm ( http://forge.ow2.org/projects/asm ). I've also change the code to combine the 2 methods into 1 method:

java.lang.AssertionError: 
Expectation failure on verify:
getHighlighter(): expected: 1, actual: 0
at org.easymock.internal.MocksControl.verify(MocksControl.java:184)
at org.easymock.EasyMock.verify(EasyMock.java:2038)
at net.TestMaxLength.testEmptyText(TestMaxLength.java:98)

But now I'm having a different error on verify:

 java.lang.AssertionError: Expectation failure on verify: getHighlighter(): expected: 1, actual: 0 at org.easymock.internal.MocksControl.verify(MocksControl.java:184) at org.easymock.EasyMock.verify(EasyMock.java:2038) at net.TestMaxLength.testEmptyText(TestMaxLength.java:98) 

This is caused when executing EasyMock.verify() statement on mockComponent.

I recommend using a mocking framework , such as EasyMock . Mocks allow you to configure dependencies with the desired behaviour for your tests. In your case, you need a mock DocumentEvent and ideally another one for component , which I guess is a class member.

The two aspects to unit testing

  • how to test, i.;e. the technical details of assembling the right set of objects in the right state required for the test to run properly (aka the _test fixture), and
  • what to test, ie the scenarios to validate.

How to test

Eclipse supports JUnit out of the box, so you may quickly generate new JUnit testcases (in Project Explorer context menu: New -> (Other ->) JUnit -> JUnit Test Case), then run it by clicking on the Run button.

Setting up the test fixture in your case would look something like this, using EasyMock (and assuming you can pass the component as a constructor parameter to your tested class):

private Component mockComponent;
private ClassUnderTest classUnderTest;
private DocumentEvent mockEvent;
private Document mockDocument;
private Highlighter mockHighlighter;

@Before
public void setUp() {
    mockComponent = createMock(Component.class);
    classUnderTest = new ClassUnderTest(mockComponent);
    mockEvent = createMock(DocumentEvent.class);
    mockDocument = createMock(Document.class);
    expect(mockEvent.getDocument()).andStubReturn(mockDocument);
    expect(mockDocument.getLength()).andReturn(1);
    mockHighlighter = createMock(Highlighter.class);
    expect(mockComponent.getHighlighter()).andReturn(mockHighlighter);
}

@Test
public void testEmptyText() {
    expect(mockDocument.getText(0, 1)).andStubReturn("");
    mockHighlighter.removeAllHighlights();
    replay(mockComponent, mockEvent, mockDocument, mockHighlighter);

    classUnderTest.handle(mockEvent);

    verify(mockComponent, mockEvent, mockDocument, mockHighlighter);
}

This test assumes that maxMessageSize is at least 1 by default - setting maxMessageSize up for the test is left to you as an exercise as the code snippet you published gives no clue for that.

What to test

The method you show gets text from the document associated with the event, then based on its length, it does different things. I would write at least the following unit tests for this:

  • empty document text with maxMessageSize == 0
  • empty document text with maxMessageSize > 0
  • nonempty document text with maxMessageSize == text.length()
  • nonempty document text with maxMessageSize > text.length()
  • nonempty document text with maxMessageSize < text.length() and addHighlight() throwing BadLocationException

Notes

  1. sensing the BadLocationException is a bit tricky, since all it produces is an output to stdout; luckily, you can easily reassign stdout via System.setOut . However, you may want to consider improving exception handling, at least by using a logging framework instead of printing to stdout.
  2. from the code it seems that other methods (such as removeAllHighlights() and/or getText() ) may also throw BadLocationException , however the try-catch blocks are not well organized. I would consider adding more unit tests where those methods throw, and after that, refactoring the exception handling code.

Update

I thought there was something wrong that I was doing...Can you please provide me with the modified/corrected code please???

Your testSetLength method is not really testing anything - you need assert statements (and/or EasyMock verification) in order for your unit tests to actually verify some behaviour. However, it provides the missing clue for setting up the tested class. So I try to unify your two test methods to create one which is hopefully working (I am writing from memory, so I can't guarantee it will all compile and run perfectly at first try) :

  @Test 
  public void testEmptyText() { 
    // set up the test class with a specific max length
    classUnderTest = new MaxLength(125); 
    // this shall be called from inside decorate()
    mockDocument.addDocumentListener(classUnderTest); 
    // the mock document shall always return an empty text
    EasyMock.expect(mockDocument.getText(0, 1)).andStubReturn(""); 
    // we expect this to be called from inside handle()
    mockHighlighter.removeAllHighlights();
    // start replay mode
    EasyMock.replay(mockComponent, mockEvent, mockDocument, mockHighlighter); 
    // inject mock component into tested object
    maxListener.decorate(mockComponent); 

    // call the tested method
    classUnderTest.handle(mockEvent); 

    // verify that all expected calls to the mocks have been made    
    EasyMock.verify(mockComponent, mockEvent, mockDocument, mockHighlighter); 
  }

When you write a unit test, you try to test if (in this case) the method does what it is supposed to do. You should not look at the implementation and write your test from that. Instead, you should think about what inputs the method should be able to handle, and what should be the result (returned value and/or side effects) after the method has been called.

Then you should write one or more tests that calls the method with valid and and invalid inputs and make the test confirm that the results matched what you thought would happen.

This was a short and incomplete description, read more at Wikipedia and junit.org .

Here is an old (2005) but working guide to JUnit in Eclipse .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM