为 Junit 测试编写测试用例

发布于 2024-09-12 11:45:23 字数 3539 浏览 3 评论 0 原文

作为一名开发人员,我是单元测试的新手,需要编写一个测试用例来对以下代码进行单元测试。有人可以在这里帮助我,并给我一些关于如何在 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()); 
    } 
} 

谢谢


更新

由于某种原因,当我运行测试用例时,我根本没有得到任何覆盖。我在这里做错了什么吗?进一步的研究表明我需要使用 test.perform() 方法来调用我想要测试的方法。这是正确的吗?你能建议一下吗?代码如下:

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); 
  }     
}

decorate(JtextComponent jComponent) 方法存在于要测试的类 (MaxLength) 中,并定义为:

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发现问题不是 Component 类,而是我需要 asm (http://forge. ow2.org/projects/asm)。我还更改了代码以将 2 种方法合并为 1 种方法:

public void testEmptyText() 
{ 
maxSizeListener.decorate(mockComponent);
//mockHighlighter.removeAllHighlights(); 
EasyMock.replay(mockComponent, mockEvent, mockDocument, mockHighlighter); 
maxSizeListener.handle(mockEvent); 
EasyMock.verify(mockComponent, mockEvent, mockDocument, mockHighlighter); 
} 

但是现在我在验证时遇到了不同的错误:

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)

这是在执行 EasyMock.verify 时引起的mockComponent 上的 () 语句。

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:

public void testEmptyText() 
{ 
maxSizeListener.decorate(mockComponent);
//mockHighlighter.removeAllHighlights(); 
EasyMock.replay(mockComponent, mockEvent, mockDocument, mockHighlighter); 
maxSizeListener.handle(mockEvent); 
EasyMock.verify(mockComponent, mockEvent, mockDocument, mockHighlighter); 
} 

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

若相惜即相离 2024-09-19 11:45:23

我建议使用模拟框架,例如EasyMock。模拟允许您使用测试所需的行为来配置依赖项。在您的情况下,您需要一个模拟 DocumentEvent ,理想情况下还需要另一个用于 component 的模拟,我猜它是一个类成员。

单元测试如何测试的两个方面

  • ,即正确运行测试所需的以正确状态组装正确对象集的技术细节(也称为 _test 固定装置),以及
  • 要测试的内容,即要验证的场景。

如何测试

Eclipse 支持开箱即用的 JUnit,因此您可以快速生成新的 JUnit 测试用例(在 Project Explorer 上下文菜单中:New -> (Other ->) JUnit -> JUnit Test Case),然后通过单击运行它在运行按钮上。

使用 EasyMock 在您的案例中设置测试装置看起来像这样(并假设您可以将组件作为构造函数参数传递给测试的类):

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);
}

此测试假设 maxMessageSize 至少为 1默认情况下 - 为测试设置 maxMessageSize 留给您作为练习,因为您发布的代码片段没有提供任何线索。

测试内容

您展示的方法从与事件关联的文档中获取文本,然后根据其长度执行不同的操作。我至少会为此编写以下单元测试:

  • 带有 maxMessageSize == 0 的空文档文本
  • 带有 maxMessageSize > 的空文档文本0
  • 非空文档文本,maxMessageSize == text.length()
  • 非空文档文本,maxMessageSize > text.length()
  • 非空文档文本,其中 maxMessageSize < text.length()addHighlight() 抛出 BadLocationException

注意

  1. ,检测 BadLocationException 有点棘手,因为它产生的只是输出到标准输出;幸运的是,您可以通过 System.setOut。但是,您可能需要考虑改进异常处理,至少通过使用日志记录框架而不是打印到标准输出。
  2. 从代码来看,其他方法(例如 removeAllHighlights() 和/或 getText()) 也可能抛出 BadLocationException,但是 < code>try-catch 块组织得不好。我会考虑在这些方法抛出的地方添加更多单元测试,然后重构异常处理代码。

更新

我认为我做错了什么......你能给我提供修改/更正的代码吗???

您的 testSetLength 方法并未真正测试任何内容 - 您需要断言语句(和/或 EasyMock 验证)以便单元测试真正验证某些行为。然而,它为设置测试类提供了缺失的线索。因此,我尝试统一您的两种测试方法来创建一个有望正常工作的方法(我是从内存中编写的,所以我不能保证它在第一次尝试时就能完美编译和运行):

  @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); 
  }

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, i.e. 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); 
  }
小嗷兮 2024-09-19 11:45:23

当您编写单元测试时,您尝试测试(在本例中)该方法是否执行其应该执行的操作。您不应该查看实现并从中编写测试。相反,您应该考虑该方法应该能够处理哪些输入,以及调用该方法后应该产生什么结果(返回值和/或副作用)。

然后,您应该编写一个或多个测试,使用有效和无效的输入调用该方法,并使测试确认结果与您认为会发生的情况相符。

这是一个简短且不完整的描述,请在 Wikipediajunit.org

这是一个旧的(2005 年)但有效的指南 Eclipse 中的 JUnit

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文