I have a test :
#Test
testLogin {
String returnValue = login(username, password)
}
Once this test completes I would to test the value of returnValue in a separate test. returnValue is also a method parameter for another method :
#Test
testVal {
performTest(returnValue)
}
To achieve this I could declare returnValue as a global variable and then ensure the tests run in order using #FixMethodOrder(MethodSorters.NAME_ASCENDING) but this seems like a non standard and unclean approach ?
Does this imply that the code which is being tested should be re-factored ?
What are the alternatives ?
Such test
#Test
public void testLogin() {
String returnValue = login(username, password)
}
doesn't have much value. The only thing it tests is that method login doesn't throw an exception and I am pretty sure that it is not what you want to test. Where are the assertions? The following implementation satisfies this test:
public String login(Object a, Object b) {
return null;
}
Your test should look like this:
#Test
public void successfulLoginReturnsExpectedResponseCode() {
String responseCode = login(username, password)
assertThat(responseCode, is(equalTo("SUCCESSFUL_LOGIN")));
}
If the login method does nothing, the return value will be incorrect.
This example uses hamcrest for better diagnostics and readability. You can also use assertEquals.
Regarding your question about tests sharing variables, it is very important that your tests (no matter whether they are unit test, integration tests or acceptance tests) do not share anything and are independent. Otherwise you will run into problems such as failing test because the other test didn't run or the tests were run in different order. You should be able to run any subset of tests in any order.
You should also consider a better name of the test, so it describes what the code under test should be doing. For example successfulLoginReturnsExpectedResponseCode().
Related
I am working on spring based project and writing unit test case using JUnit + Mockito. I am facing a problem while stubbing boolean value to a private method of same test class (after changing access level to public, still I have failed to stub the boolean value).
Below code snippet shows the simulation of same problem
class ABC {
public String method1(User userObj){
String result = "";
if(!isValidUser(userObj.getSessionID())){
return "InvalidUser";
} else {
// execute some logic
}
return result;
}
private boolean isValidUser(String sessionId) {
// Here it calls some other class to validate the user
if (sessionId == null || UserSessionPool.getInstance().getSessionUser(sessionId) == null) {
return false;
} else {
return true;
}
}
}
Here, I would like to write a test case for method1(). In class ABC I have a method called isValidUser() which helps to identify the user with in a session by looking into a global session pool which holds all logged-in used details i.e. UserSessionPool.getInstance().getSessionUser(sessionId).
While testing method1(), the moment test controller triggers isValidUser(userObj.getSessionID()) I would like to return true from isValidUser() method, so that I can continue to test rest of the implementation logic.
So far I have tried following ways using spy and mocked object to call the isValidUser() method and try to return true but nothing worked well.
Using PowerMockito
PowerMockito.doNothing().when(spyed_ABC_ClassObject, "isValidUser", true);
or
PowerMockito.doReturn(true).when(cntrl, "isValidUser", Mockito.anyString());
Using Whitebox
Whitebox.invokeMethod(spyed_ABC_ClassObject, "isValidUser", Mockito.anyString());
Using Mockito.when
when(spyed_ABC_ClassObject.isValidUser(Mockito.anyString())).thenReturn(true);
or
Mockito.doNothing().when(spyed_ABC_ClassObject).isValidUser(Mockito.anyString());
The other answer is: fix your design instead of turning to the big PowerMock hammer.
Yes, PowerMock allows you to mock static methods. But you should understand: static is an abnormality in good OO design. You only use it when you have very good reasons. As it leads to tight coupling between your classes, and surprise: it breaks your ability to write reasonable unit tests. Yes, PowerMock works; but sometimes, it does not. When your classes grow, and you do more and more things "statically", because, you know, PowerMock will do the job ... be prepared for bizarre fails at some point, that can take hours to hunt down; without ever finding real bugs in your production code.
So, consider an alternative:
Do not use static method calls. And if there is some static method around that you can't touch; consider building a small interface around that.
Instead: use dependency injection and simply pass objects implementing some interface into your production code. Because you can mock such objects without the need for PowerMock(ito).
In that sense: you simply created hard to test code. Now you intend to fix that using PowerMock. The other way (much more reasonable in my eyes) is to learn how to write testable code in the first place. Here is a good starting point for that.
Can you please try this out.
#Before
public void setUp() {
UserSessionPool mockConnectionPool = Mockito.mock(UserSessionPool.class);
}
#Test
public void testName() throws Exception {
//given
PowerMockito.mockStatic(UserSessionPool.class);
BDDMockito.given(UserSessionPool.getInstance()(...)).willReturn(mockConnectionPool);
Mockito.when(mockConnectionPool.getSessionUser(Mockito.anylong())).thenReturn(something);
//then
PowerMockito.verifyStatic();
}
Hope this helps. Happy coding !
Background: I'm executing tests with TestNG and I have a class annotated with #Test that generates a number, or ID if you will, and that same number is the input value of my second test. Is it possible to pass values between TestNG tests?
Sure. For example if you have two tests that is related you can pass the values from one test to another via test context attributes:
#Test
public void test1(ITestContext context) { //Will be injected by testNG
/* Do the test here */
context.setAttribute("myOwnAttribute", "someTestResult");
}
#Test(dependsOnMethods = "test1")
public void test2(ITestContext context) { //Will be injected by testNG
String prevResult = (String) context.getAttribute("myOwnAttribute");
}
You should create one test that handles whole case. Tests can't depend on each other, it's considered as bad practise. If you are using maven order of tests execution can be different in different environments.
Bad practice or not, it can be accomplished by simply using class fields. Just make sure your cases are executed in predictable order (eg. using #Test(priority) or dependsOn TestNG feature).
Is there any way I can get the test result in the teardown (#After) method? I'd like to do clean up after the tests depending on the result.
Could not find much details about #After in the junit docs.
The closest thing to what you're asking for would probably be the TestWatcher rule. That won't give you access to a returned result or anything, but you can use it (or create your own TestRule and combined with the Description object, you could annotate your methods differently to indicate what sort of clean-up is necessary.
Yes, if you use TestNG, it is a standard function, your #After method can look like this:
#AfterTest
public void cleanUp( ITestResult result ) {
boolean success = result.isSuccess();
....
If there is no standard possibility (I'm pretty sure there was no possibility in JUnit 3.x), you can just
write a Listener,
push the Listener-events to a static Collection,
and gather them from your #After- Method.
Why not set the result of a test in a class member and then act on it in the #After method?
public enum TestResult {
...
}
public class TestClass {
private TestResult result;
...
#Test
public void aTest() {
// set up test
// call class under test
// assert something and set result based upon outcome
this.result = ...;
}
...
#After
public void teardown() {
// clean up based upon this.result
}
}
I suspect you would not have too many different results and a finite set will suffice.
I am using something alike JamesB suggested. You might get to the point where you have to add timeouts to the tests, then =>>
"setting the result of a test in a class member and then act on it in the #After method" would not always work if you have more than 1 assert. That's is my problem today, when i have testCaces that timeout, but my afterClass is assuming everything went smooth because the most recent assert has passed..
I was wondering if there is an annotation or way to only execute test if pre-conditoin meets?
I have a situation where some tests are relevant until a specific date is met.
I use JUnit, Mockito.
Thanks
You can do this by using Assume.
In below shown example, I want to check status in case if precondition==true and I want to assert that exception is thrown in case of precondition==false.
#Test
public final void testExecute() throws InvalidSyntaxException {
Assume.assumeTrue(precondition); // Further execution will be skipped if precondition holds false
CommandResult result = sentence.getCommand().execute();
boolean status = Boolean.parseBoolean(result.getResult());
Assert.assertTrue(status);
}
#Test(expected = InvalidSyntaxException.class)
public final void testInvalidParse() throws InvalidSyntaxException {
Assume.assumeTrue(!precondition);
CommandResult result = sentence.getCommand().execute();
}
Hope this helps to you.
You can use the Assume class
A set of methods useful for stating assumptions about the conditions
in which a test is meaningful. A failed assumption does not mean the
code is broken, but that the test provides no useful information. The
default JUnit runner treats tests with failing assumptions as ignored.
so at the start of your test you can write
Assume.assumeThat("Condition not true - ignoreing test", myPreCondition);
and JUnit will ignore this test if myPreCondition is false.
What are the patterns and dos and don'ts when one is writing tests for Javolution tests? In particular I was wondering:
TestCase.execute() does not allow throwing of exceptions. How to deal with them? Rethrow as RuntimeException or store in a variable and assert in TestCase.validate() or something?
Are there any graphical runners that show you the tests that fail, i.e. in Eclipse? Perhaps someone wrote a JUnit-Wrapper such that I could use the Eclipse JUnit Runner?
The javadoc and javolution sources give some examples and design rationale.
See also an article on serverside.
Javolution tests contain exactly one test, and the exercising of the tested code is separated from the validation into different methods execute() and validate(). Thus the same testclass can be used both for regression tests and speed tests (where the call to validate() is omitted). Also the execution of many tests is trivially parallelizable.
A disadvantages of this separation is: you will get more memory consumption, since the results of the execution of the exercised code needs to be saved until calling validate(). (Freeing those results in tearDown is probably a good idea.)
And if validate comes from a different class than exercise then it might be difficult to debug a failure.
You can get some kind of graphical testrunner by using the following JUnit adapter and running it in eclipse. You can start / debug the failed tests separately. Unfortunately the graphical representation does not include anything about the actual test - it just shows the numbers [0], [1], etc.
#RunWith(Parameterized.class)
public class JavolutionJUnit4Adapter {
protected final javolution.testing.TestCase test;
public JavolutionJUnit4Adapter(javolution.testing.TestCase testcase) {
this.test = testcase;
}
#org.junit.Test
public void executeTest() throws Exception {
enter(REGRESSION);
try {
new javolution.testing.TestSuite() {
#Override
public void run() {
test(test);
}
}.run();
} finally {
exit();
}
}
#Parameters
public static Collection<javolution.testing.TestCase[]> data() {
javolution.testing.TestSuite fp = new WhateverSuiteYouWantToRun();
List<javolution.testing.TestCase> tests = fp.getTestCases();
Collection<javolution.testing.TestCase[]> res = new ArrayList<javolution.testing.TestCase[]>();
for (javolution.testing.TestCase t : tests) {
res.add(new javolution.testing.TestCase[] { t });
}
return res;
}
}