I'm building a Wicket 1.6 application.
In this I have a Parameter class and a FillParameter class to translate org.apache.wicket.PageParameters to my own Parameter class. The Parameter class has defaults (which are set during creation), the FillParameter has min/max values I check on. Both the default values as the min/max values are loaded from a text_resource.properties file using StringResourceModel.
example (line 15):
private int offset = Integer.parseInt((new StringResourceModel("bla.bla.bla.offset", null)).getString());
So far so good. This is working fine in my Wicket application.
Now I'm working on my junit tests and I want to test my FillParameters.class. This is a snippet from my current FillParametersTest.class:
private WicketTester wicketTester;
#Mock
Localizer localizer = mock(Localizer.class);
#Before
public void init() {
wicketTester = new WicketTester(MyApplication.class);
when(localizer.getString(eq("bla.bla.bla.offset"), (Component)anyObject(), anyString())).thenReturn("0");
wicketTester.getApplication().getResourceSettings().setLocalizer(localizer);
}
#Test
public void fillParametersGoodTest() {
PageParameters pageParameters = new PageParameters("pOffset=0");
Parameters parameters = FillParameters.fillParameters(pageParameters, parameters);
Assert.assertEquals(parameters.getOffset(), 0);
}
Alas, this is not working. The test seems to find the resource, but it doesn't get the value from that resource, resulting in:
java.lang.NumberFormatException: null
at java.lang.Integer.parseInt(Integer.java:454)
at java.lang.Integer.parseInt(Integer.java:527)
at bla.bla.bla.Parameters.<init>(Parameters.java:15)
at bla.bla.bla.FillParametersTest.fillParametersGoodTest(FillParametersTest.java:63)
(line 15 in Parameters is the example I've mentioned above)
I've been searching for a solution to my problem, but I can only find good examples on how to read from a resource in the test class, not how to make it work in a application class called by the test class.
I hope I've made my problem clear, and that someone can help me with it. I'm quite new to wicket, but eager to learn.
Problem: how can I read text_resources during junit test with StringResourceModel?
Answer 27 feb 2015
Ok, so I've refactored my whole application and now I've got the code working, and it's actually very simple
private WicketTester wicketTester;
#Before
public void init() {
tester = new WicketTester(MyApplication.class);
}
#Test
public void fillParametersGoodTest() {
MockRequestParameters pageParameters = new MockRequestParameters();
pageParameters.addParameterValue("offset", "0");
FillParameters fp = new FillParameters();
Parameters parameters = fpo.fillParameters(pageParameters, parameters);
Assert.assertEquals(parameters.getOffset(), 0);
}
I'm pretty sure the problem is in your Mockito rule (the when):
when(localizer.getString(eq("bla.bla.bla.offset"), (Component)anyObject(), anyString())).thenReturn("0");
It doesn't match the real call and thus later the value is null.
Play in this area.
Related
Console Output
Please help me to fix the below issue in Selenium WebDriver with Java.
I am validating eComm web based application. I have couple of test cases.
1. Sign in to the application
2. Add to item to the cart. This test case is a continuation of first test case. It means that after sign in, user is gonna add the item to the cart.
I have 2 class files, In that I have given #Test condition in both the class files.
In CommonFunctions class file, I am lauching browser in #BeforeSuite section. And closing the browser in #AfterSuite section.
I am doing it in Page object model and executing from TestNG XML.
On running the suite, First test case is getting passed. When it comes to the second test case (In the #Test condition present in the 2nd class file), the in it entering into the #Test section but getting failed immediately with out any reason.
I have tried with Implicit, Explicit wait and even thread.sleep as well. But no luck. Please can some one take a look and suggect me.
Appreciate your help!
I assume that it is getting failed for some exception and the stack trace is not getting printed somehow. Try explicitly getting it printed by:
#Test
public void SecondTestCase(){
try{
yourSecondTestCase;
}
catch(Throwable e){
e.printStackTrace();
}
}
Just don't reuse the driver.
Create it in #BeforeMethod then quit it in #AfterMethod and you should not meet any issues.
Update answering a comment question below:
In general it's not a good idea to have the tests depending on each other.
Regardless of how special you think your case is, you should never do it if you want to keep your dignity.
This does not neccessarily mean that you can't reuse 'logic' in tests, it just means that you should not expect any other test to have executed before the current one.
Let's put some thought about it:
Why would you want to do it at first place?
What is the effect that you're seeking?
My blind-guess answers are:
You want to have the login test executed first.
This will help you avoid repeating the same login code in all of the remaining tests, and you save time from starting/stopping the driver.
If my guesses are correct, then I can tell you that it's perfectly normal to want those things, and that everyone who ever needed to write more than 2 tests has been there
You may ask:
Am I not trying to achieve the same thing?
Where is my mistake then?
The following answers can be considered brief and quite insufficient compared to the truth that lies beneath, but I think they will serve you as a good starting point for where you're heading at.
Yes, you're trying to achieve the same thing.
Your approach can't be called mistake, but negliance - you're trying to write automated tests with Selenium while you lack basic coding skills. It's actualy not so bad, because you didn't knew what you're getting into, but after reading this you have the choice of either letting it slip or begin the journey to personal improvement. Take some time to learn Java - a really good starter would be the 'Thinking in Java' book. Do make the exercises after each chapter and the experience that you'll gain will be priceless. The book will help you get familiar with the Java language features and good idea of how code organization works.
Enough with the general notes, below is a simple guide for you to follow in implementing v0.1 of your newly-born 'automation project'.
(Yes, it is 'project' and 'framework' is having completely different meaning, to be clear.)
First you need to decide how to approach the page objects.
(Based on my own experience)
the best way to do it is to keep all the business-logic inside the page objects and by business-logic I mean:
all the methods that perform some action,
and all the methods that retrieve some data.
Examples include doSomething / getSometing / setSomething / isSomething / canSomething / waitSomething and so on.
You should not be doing any assertions inside the page objects
You should never throw AssertionError from your page objects
If you need to throw something from page-object method/constructor just
throw IllegalArgumentException
or RuntimeException.
All the assertions should happen exclusively in the test-method-body
You should never write 'assert...' statement outside #Test method
You can have Util classes to do some data transformations
but do not ever write assertion logic inside them
rather expose methods with boolean/other return type and assert on their result.
The following example is one of the best I've ever seen:
// Don't do this:
ColorVerifications.assertAreSame(pen.getColor(), ink.getColor());
// If you do, you'll eventually end-up having to write this:
ColorVerifications.assertAreNotSame(pen.getColor(), ink.getColor());
// Do this instead:
Assert.isTrue(ColorUtil.areSame(pen.getColor(), ink.getColor());
// Then you can actually 'reuse' the logic that's already in the Assert class:
Assert.isFalse(ColorUtil.areSame(pen.getColor(), ink.getColor());
// NOTE: Regarding the term "code reuse"
// - it is NOT referring to "reusing your own code"
// - it IS referring to "reusing all the existing code"
The idea is to clearly communicate both the assert intention and how the check is done.
Always keep the logic of 'checking' and 'asserting' separate, becuse those words are having different semantics.
It is really important to put a good amount of thinking when naming classes / methods / variables - really!
Don't be afraid to rename it when you come up with a better fit - go for it on the spot!
Now back to our page obects and login stuff - I won't be diving much into it but, you'll get where I'm going at.
Carefully organize the #Test methods in separate classes
Keep the ones that need common setup in the same class
Keep the number of test-class methods that are not annotated with #Test to the minimum
Do not inherit between test classes to reuse logic other than
Outputs/Results folders preparaton/colletion/archiving
Logs/Reports initialization/disposal
Driver creation/cleanup
In general: prefer composition to inheritance
Put other logic in the page objects / util classes and reuse them
Have a base DriverWrapper class for the generic UI checks/interactions
Have a base PageObject class that is hosting a DriverWrapper member
Don't use the #FindBy / PageFactory model (you'r life will be happier)
Use static final By locators instead
Log everything!
logging is not included in the examples
but do assume every method's first line is logging the method name and the passed arguments
always remember - your log is your best friend
Reading what happened in the log takes considerably less time than manually debugging the code (which is pratically re-running it at half-speed)
You are writing atuomation code, not production code so you can nevver be wrong when logging additional info.
Except for the cases of passwords and confidential data
those you should never log.
Now that you have been thaught some basic ideas, lets dive into code:
Page basics
Sample DriverWrapper:
class DriverWrapper {
protected final WebDriver driver;
public DriverWrapper(WebDriver driver){
this.driver = Objects.requireNotNull(driver, "WebDriver was <null>!");
}
// it's okay to have 'checked exceptions' declared by all wait* methods
// but it is tottaly not okay to have 'checked exceptions' for the others
public WebElement waitForVisibleElement(By locator, int timeoutMillis)
throws TimeoutException { // <- the 'checked exception'
return new WebDriverWait(driver)
.withTimeout(Duration.ofMillis(timeoutMillis))
.pollingEvery(Duration.ofMillis(100))
.until(
ExpectedConditions.visibilityOfElementLocatedBy(locator)
);
}
public boolean isVisible(By locator, int timeoutMillis){
try{
return waitForVisibleElement(locator, timeoutMillis) != null;
catch(TimeoutException ignored){
return false;
}
}
// .get(String url){...}
// .click(By locator){... elementToBeClickable(locator) ....}
// .typeInto(bool shouldLog, By locator, CharSequence... keys){...}
// .typeInto(By locator, CharSequence... keys){typeInto(true, locator, keys);}
// you got the idea ;)
}
Sample PageObject:
class PageObject{
protected final DriverWrapper driver;
public PageObject(WebDriver driver){
this.driver = new DriverWrappr(driver);
}
}
Sample LoginPage:
class LoginPage extends PageObjet{
// NOTE: keep the locators private
private static final By USERNAME_INPUT = By.id("usernameInput");
private static final By PASSWORD_INPUT = By.id("passwordInput");
private static final By LOGIN_BUTTON = By.id("loginButton");
private static final By ERROR_MESSAGE = By.id("errorMessage");
public LoginPage(WebDriver driver){
super(driver);
}
public LoginPage goTo(){
driver.get(url);
return this;
}
public void loginAs(String user, String pass){
// NOTE:
// Do not perform navigation (or other actions) under the hood!
// Resist the urge to call goTo() here!
// Page object methods should be transparent about what they do.
// This results in better level of control/transparency in the tests.
driver.typeInto(USERNAME_INPUT, user);
driver.typeInto(PASSWORD_INPUT, pass);
driver.click(LOGIN_BUTTON);
}
public boolean isErrorMessageVisible(int timeoutMillis){
// NOTE: We delegate the call to the driver
// Allowing the page-object to later define it's own isVisible method
// Without having collision with driver methods.
return driver.isVisible(ERROR_MESSAGE, timeoutMillis);
}
}
Infrastructure basics
Sample DriverManager class:
class DriverManager{
private static WebDriver driver;
public static WebDriver getDriver(){
return driver;
}
public static void setDriver(WebDriver driver){
// NOTE: Don't do null checks here.
DriverManager.driver = driver;
}
public static WebDriver createDriver(String name){
//...
return new ChromeDriver();
}
Sample TestBase class:
class TestBase{
// NOTE: just define the methods, do not annotate them.
public static void setUpDriver(){
// In v0.1 we'll be sharing the driver between tests in same class
// Assuming the tests will not be running in parallel.
// For v1.0 you can improve the model after reading about test-listeners
WebDriver driver = DriverManager.getDriver();
if(driver != null){
return;
}
driver = DriverManager.createDriver("chrome");
DriverManager.setDriver(driver);
}
public static void tearDownDriver(){
WebDriver driver = DriverManager.getDriver();
if(driver != null){
driver.quit();
DriverManager.setDriver(null);
}
}
}
Finally - a test class:
class LoginTests extends TestBase{
private LoginPage loginPage;
#BeforeClass
public static void setUpClass(){
setUpDriver();
}
#AfterClass
public static void tearDownClass(){
tearDownDriver();
}
#BeforeMethod
public void setUp(){
// actions, that are common for all test cases in the class
loginPage = new LoginPage(DriverManager.getDriver());
loginPage.goTo();
}
#AfterMethod
public void tearDown(){
// dispose the page objets to ensure no local data leftovers
loginPage = null;
}
#Test
public void testGivenExistingCredentialsWhenLoginThenNoError(){
loginPage.loginAs("TestUser", "plain-text password goes here");
boolean errorHere = loginPage.isErrorMessageVisible(30 * 1000);
Assert.assertFalse(errorHere, "Unexpected error during login!");
}
#Test
public void testGivenBadCredentialsWhenLoginThenErrorShown(){
loginPage.loginAs("bad", "guy");
boolean errorHere = loginPage.isErrorMessageVisible(30 * 1000);
Assert.assertTrue(errorHere, "Error message not shown!");
}
}
That's all there is to it.
Hope you enjoyed the ride.
I'm looking to run JUnit 4.12+ programmatically, and a cursory search for doing so yielded (amongst many other similar posts) this answer, which prescribes the following basic solution:
#RunWith(Suite)
#Suite.SuiteClasses ({
MyTestClass1.class,
MyTestClass2.class
})
public class MyTestSuite {
}
Result testResults = JUnitCore.runClasses(MyTestSuite.class);
...and I was able to get this working, no sweat. So far so good!
Problem is: I have some pretty sophisticated test classes that need to be instantiated/injected with very specific properties at runtime...not something that can be done from inside a no-arg constructor. But the above method (specifying to just run any old instance of a set of classes) doesn't allow you to instantiate your test classes, configure them, and then run them.
Is there a way to do this? I couldn't find anything looking at the JUnit API. I am looking for something like:
MyTestClass1 mtc1 = new MyTestClass1(...);
MyTestClass2 mtc2 = new MyTestClass2(...);
Result testResults = JUnitCore.run(mtc1, mtc2);
You probably need custom runner to achieve that. Junit 4/5 comes with third party runner that can perform dependency Injection for Constructors and Methods. Few runner which are pretty popular are Mockito(MockitoJUnitRunner) and SpringJUnit4ClassRunner in case you are using Spring. You can check out custom runner and implementation details at:
https://github.com/junit-team/junit4/wiki/Custom-runners
I got this working with a custom Runner with sample (Groovy pseudo-code) as follows:
class MyRunner extends Runner {
#Override
Description getDescription() {
return null
}
#Override
void run(RunNotifier notifier) {
// LoginTests.class is a test class I want to run
LoginTests loginTests = new LoginTests(<my args here>)
Description description = Description.createSuiteDescription(LoginTests)
notifier.fireTestStarted(description)
try {
log.info("About to doSomething()...")
loginTests.doSomething()
log.info("Did it...")
notifier.fireTestFinished(description)
} catch(Throwable throwable) {
log.info("doSomething() failed...")
notifier.fireTestAssumptionFailed(new Failure(description, throwable))
}
}
}
Result testResults = new JUnitCore().run(Request.runner(new MyRunner()))
I am trying to understand Unit testing and how the correct classes are being fetched on test time,
I'm having a hard time understanding exactly what is going on behind the scenes and how safe/correct my usages for this are.
This is a very simple example of what i am trying to do, i wrote it here inline so it probably contains some errors, please try to ignore them, as stupid as they may be.
A very simple project directory:
ba/src/main/java/utils/BaUtils.java
ba/test/main/java/utils/BaUtilsTest.java
notBa/src/main/java/im/BaObj.java
BaUtils.java code:
package com.ba.utils;
import notBa.im.BaObj;
public class BaUtils{
public String doSomething(BaObj obj){
obj.doSomething();
}
}
I would like to test BaUtils wihtout actually calling doSomething, and i can't change anything on BaObj class or notBa package. I know that i can (by 'can' i mean it will work) add a new java file to 'ba' project (ba/test/java/notBa/main/java/im/BaObj.java) that will have the same package as the original BaObj, and at runtime the test will import this one instead of the real one, so BaUtils code is tested but BaObj code is not excecuted.
that should look something like like :
package notBa.im.Baobj
public class BaObj{
public void doSomething(){
System.out.println("Did something");
}
}
My questions are (And thank you for reaching this far):
How does this work (Reading references would be great).
Is this kind of test building considered 'good' or 'safe' ?
Thanks!
The solution is to use a mocking framework (I for myself like Mockito).
The test would look like this:
class BlaUtilTes{
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Mock
Blaobj blaobj;
#Test
public void doSomething_WithMockedBlaobj_callsDosomethingOnBlaobj(){
// arrange
BlaUtil blaUtil= new BlaUtil();
// act
blaUtil.doSomething(blaobj);
// assert
Mockito.verify(blaobj).doSomething();
}
}
find more information here http://www.vogella.com/tutorials/Mockito/article.html#testing-with-mock-objects
Your BaUtilsTest class should look like this.. I have used mockito for for mocking external dependencies. Also I changed the method return type to String for easy understanding.
#RunWith(MockitoJUnitRunner.class)
class BaUtilsTest {
BaUtils util;
#Mock
BaObj mockBaObj;
#Before
public void setup() {
util = new BaUtils();
}
#Test
public void testDoSomething() {
Mockito.when(mockBaObj.doSomething()).thenReturn("did the work using mock");
String result = util.doSomething(mockBaObj);
Assert.assertEquals("did the work using mock", result);
}
}
I have a class which writes messages to some logs. The class is a utility which doesn't do anything else, it runs in the background, checks a few things and logs them. I'm wondering if it's possible for me to verify in a unit test that the log has been written to without caring about what it is actually writing. Here's my class being tested:
//imports...
public class MyClass {
private static Log log = LogFactory.getLog(MyClass.class);
public MyClass() {
log.info("MyClass is being created.");
}
public void doThing() {
if( everything_is_fine ) {
log.info("This is a message to say everything is fine.");
} else {
log.error("Uh oh...");
}
}
}
And my tester class:
// imports ...
#RunWith(PowerMockRunner.class)
#PrepareForTest({MyClass.class,LogFactory.class})
public class MyClassTest {
Log mockLog;
#Before
public void setup() {
PowerMockito.mockStatic(LogFactory.class);
mockLog = mock(Log.class);
PowerMockito.when(LogFactory.getLog(MyClass.class)).thenReturn(mockLog);
}
#Test
public void test_everything_is_ok() {
MyClass mything = new MyClass(); // should write to log.info
mything.doThing(); // should write to log.info
verify(mockLog, atLeastOnce()).info(anyString());
verify(mockLog, never()).error(anyString());
}
#Test
public void test_everything_is_not_ok() {
MyClass mything = new MyClass(); // should write to log.info
// do something which makes things not ok
mything.doThing(); // should write to log.error
verify(mockLog, atLeastOnce()).info(anyString());
verify(mockLog, atLeastOnce()).error(anyString());
}
}
When I run the tests, I expect that the log.info() is invoked for both tests, and the log.error() is invoked only for the second. However I'm getting a "Wanted but not invoked" for the log.info for both tests. and for log.error on the second. So either:
1) My code is broken and not writing to the log, or
2) My test is broken.
I'm thinking that I've messed up something in my test, probably something really obvious, so has anyone had experience testing something like this who could help me out? Any and all help will be appreciated.
UPDATE:
Thanks to those who helped out, I've got a solution now.
After playing around with the code for a bit, I discovered that there seems to be an issue with the initialization of the log. Doing private static Log log = LogFactory.getLog(MyClass.class); didn't seem to use the mock correctly, so if I move it to the constructor it seemed to be mocked OK and my tests all work as expected:
public class MyClass {
private static Log log;
public MyClass() {
MyClass.log = LogFactory.getLog(MyClass.class);
log.info("MyClass is being created.");
}
// etc ...
}
I've got it working now, but can anyone explain why initializing the log the first way didn't work? Or perhaps point me to somewhere which explains it? I'm not sure if there's a gap in my understanding of how Java initializes objects or if it's a limitation of mocking frameworks.
You can make an abstraction over the Logger like we did here in our project:
https://github.com/4finance/uptodate-gradle-plugin/blob/master/src/main/groovy/com/ofg/uptodate/LoggerProxy.groovy
Then you have to constructors
https://github.com/4finance/uptodate-gradle-plugin/blob/master/src/main/groovy/com/ofg/uptodate/UptodatePlugin.groovy
One with LoggerProxy initialized and one for tests where you can mock it out and verify if proper text was passed. No need for dirty hacks ;)
Since I had the same problem (private static Log log = LogFactory.getLog(MyClass.class);), I'm posting what I did to solve it.
Instead of modifying logger initialization (I was limited by coding rules) I simply split test in different classes...
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.
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
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.
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.