All,
I am currently using JUnit 4 for writing test cases. I am fairly new to JUnit and finding it difficult to test my main class which takes arguments. I have specified the arguments to my JUnit test class by:
1 > Right click JUnit test class
2 > Goto Run As -> Run Configurations
3 > Select the Arguments tab and specify a value (I have entered an invalid argument i.e. the main class expects the command line argument to be converted to an int and I am passing a String value that cannot be converted to int)
However, the main class that I am testing, if the command line argument cannot be converted to a int, than I throw IllegalArgumentException. However, the JUnit does not show the testMain() method as Error or Failure. I don't think my setup is right for the JUnit class. Can anyone please guide me where I am going wrong
To test your class main method simply write something like:
#Test(expected = IllegalArgumentException.class)
public void testMainWithBadCommandLine()
{
YourClass.main(new String[] { "NaN" });
}
Change the main() method to something like this:
public static void main(String[] args)
{
MyClass myclass = new MyClass(args);
myclass.go();
}
Move the code that was in main() to the new method go(). Now, your test method can do this:
public void myClassTest()
{
String[] args = new String[]{"one", "two"}; //for example
MyClass classUnderTest = new MyClass(testArgs);
classUnderTest.go();
}
Firstly the arguments should be in the program arguments section. Normally the launching point of the application that's the main method doesn't need to be tested if you design the app to be testable.
Refactor the class
public static class ArgumentValidator
{
public static boolean nullOrEmpty(String [] args)
{
if(args == null || args.length == 0)
{
throw new IllegalArgumentException(msg);
}
//other methods like numeric validations
}
}
You can now easily test the nullOrEmpty method using junit like
#Test(expected = IllegalArgumentException.class)
public void testBadArgs()
{
ArgumentValidator.nullOrEmpty(null);
}
I think this is a better approach
Related
I am comparing two objects emsResponse and expectedEMSResponse of the same class EMSResponse in a Junit test case but the assertThat(...) test case passes despite the objects being unequal. When I try a normal equals on the two objects the output is false but the assertThat(expectedEMSResponse==eMSResponse) still passes rather than failing. Please advise.
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#ToString
#EqualsAndHashCode
public class RestconfRes {
private String response;
private int httpStatusCode;
}
#Getter
#Setter
#ToString
#EqualsAndHashCode(callSuper = true)
public class EMSResponse extends RestconfRes {
private EMSOutput output;
private EMSErrors errors;
private String message;
public EMSOutput getOutput() {
if (output == null) {
output = new EMSOutput();
}
return output;
}
}
// Junit test case
#Test
public void processJMSRequestForHappyPathTest() throws Exception {
// test case logic here
// mock logic here
EMSResponse emsResponse = processor.processJMSRequest(request);
System.out.println(" expectedEMSResponse ..." + EMSResponse.toString());
System.out.println(" processJMSRequestForHappyPathTest expectedEMSResponse ...:" + expectedEMSResponse.toString());
System.out.println("check if i am equal..."+ expectedEMSResponse.equals(emsResponse));
assertThat(expectedEMSResponse==eMSResponse);
}
Output:
expectedEMSResponse ...EMSResponse(output=EMSoutput(deviceName=null, timestamp=null, status=failure, transId=null, completionStatus=null, serviceId=null, contentProviderName=null, interfaceName=null), errors=EMSerrors(errorType=INTERNAL_FAILURE, errorTag=A41_INTERNAL_EXCEPTION, errorMessage=An internal error occurred within A41. Please contact ASG.), message=null)
emsResponse ...EMSResponse(output=EMSoutput(deviceName=device_3, timestamp=2020-07-15T16:32:31.881000, status=configuring, transId=66427-d8b5-489f-9f8f, completionStatus=in-progress, serviceId=null, contentProviderName=null, interfaceName=null), errors=null, message=null)
check if i am equal...false
Updated second sub question to this
I changed the call to:
assertTrue(expectedEMSResponse==emsResponse);
// gives a java.lang.AssertionError and
System.out.println("check if i am equal..."+ expectedEMSResponse.equals(emsResponse)); gives output
check if i am equal...false
// this test case passes Ok assertThat(emsResponse.getOutput().getTransId()).isEqualTo(expectedEMSResponse.getOutput().getTransId());
When I try printing the details of the emsResponse and expecteEMSResponse classes through toString() I get the below output:
// gives only a bean as an output
emsResponse.toString():com.myorg.myapp.interfaces.dto.emsResponse#0 bean
//gives the complete object signature
expectedemsResponse.toString():emsResponse(output=emsOutput(deviceName=device_3,
timestamp=2020-07-15T16:32:31.881000, status=configuring, transId=hello-there-489f-9f8f-abcd,
completionStatus=in-progress, serviceId=null, contentProviderName=null, interfaceName=null), errors=null, message=null)
You are probably using AssertJ because I don't think JUnit 4 or Hamcrest have a single argument version of assertThat(), and JUnit 5 doesn't have such method.
The way AssertJ assertThat() works is that the first argument of the call is the actual value that you want to perform assertions on. This returns an assertion object, which provides you a number of assertion methods.
When you call assertThat(expectedEMSResponse==eMSResponse), AssertJ just returns an assertion object for boolean type and nothing else happens.
The correct way to use it would be:
assertThat(eMSResponse).isEqualTo(expectedEMSResponse);
Now it returns an assertion object for the first argument, and then performs the isEqualTo() assertion on that one. The assertThat() call only works as an entry point to different assertions that can be performed on the first argument.
I don't think you are using assertThat correctly. Looks like you need to pass additional arguments as well. These are the method definitions:
assertThat(T actual, Matcher<? super T> matcher)
assertThat(String reason, T actual, Matcher<? super T> matcher)
Also as per the documentation, it is deprecated. Might I suggest that you use assertEquals() instead?
The documentation: https://junit.org/junit4/javadoc/latest/org/junit/Assert.html#assertThat
This does not fail because you are not using junit correctly:
#Test
public void processJMSRequestForHappyPathTest() throws Exception {
// test case logic here
// mock logic here
EMSResponse emsResponse = processor.processJMSRequest(request);
System.out.println(" expectedEMSResponse ..." + EMSResponse.toString());
System.out.println(" processJMSRequestForHappyPathTest expectedEMSResponse ...:" + expectedEMSResponse.toString());
System.out.println("check if i am equal..."+ expectedEMSResponse.equals(emsResponse));
assertThat(expectedEMSResponse==eMSResponse);
}
You should have:
assertTrue(expectedEMSResponse==eMSResponse);
assertEquals(expectedEMSResponse, eMSResponse);
Or using assertThat with assertj:
assertThat(eMSResponse).isEqualTo(expectedEMSResponse);
This should help you understand:
junit 5: https://junit.org/junit5/docs/current/user-guide/
junit 4: https://www.baeldung.com/junit-assertions
I am writing unit test for the below code using junit and mockito
public class Abc implements Runnable
{
private static ServerSocket server;
private static int port;
public Abc(int cPort)
{
port = cPort;
}
public void run()
{
init();
}
public static void init()
{
try {
server = new ServerSocket(port);
...something...
client.close();
}
}
catch(IOException e)
{
System.out.println("Exception inside init()...");
e.printStackTrace();
}
}
};
Unit test I have written
#RunWith(PowerMockRunner.class)
#PrepareForTest({ServerSocket.class})
public class abcTest {
#Mock (name = "server") //same name as private var.
ServerSocket mockServer;
#InjectMocks
Abc abc;
#Test
public void testInit() throws Exception {
int port = 1880;
Socket mockClient = Mockito.mock(Socket.class);
PowerMockito.whenNew(ServerSocket.class).
withArguments(anyInt()).thenReturn(mockServer);
abc = new Abc(port);
Abc.init();
PowerMockito.verifyNew(ServerSocket.class).withArguments(port);
}
};
But the call always go to original function definition. I am using junit 4.11 with mockito 2.28.2 and powermockito 2.0.2. I'm using java after a long time. Now its feel like kind of new. Please correct me if anything wrong in the code also.
You will need to change your PrepareForTest annotation
to #PrepareForTest({Abc.class}).
From the PowerMockito docu:
This annotation tells PowerMock to prepare certain classes for testing. Classes needed to be defined using this annotation are typically those that needs to be byte-code manipulated
In this case that refers to the class which creates the new instance of ServerSocket. ServerSocket itself is a non-final public class that does not require special handling from PowerMockito (instead Mockito can deal with this class on its own).
You could also change your test to do the following:
#Test
public void testInit() throws Exception {
int port = 1880;
ServerSocket mockServer = Mockito.mock(ServerSocket.class);
PowerMockito.whenNew(ServerSocket.class)
.withArguments(Mockito.anyInt()).thenReturn(mockServer);
Abc.port = port;
Abc.init();
PowerMockito.verifyNew(ServerSocket.class).withArguments(port);
}
(This first point is unrelated to whether the test fails or succeeds)
I do not know why you mix object's and static method behaviour together, but I think you should change that.In the test instead of creatic an ABC object, just could just set the static port variable directly.
Or alternatively change the whole ABC class into an object.
#InjectMocks failed for me as there is no default constructor
(Actually I got an error message in the console when trying to execute your code)
Additonaly you create a new instance of ABC in your test, which would have overwritten the things done by the annotations. Also as server is created during the init call, there is no need to inject a mock for it.
powermockito 2.0.2 actually depends on junit 4.12, so I am not sure what effects downgrading to an older version might have.
Socket mockClient seemed somewhat unrelated to the code your posted, so I removed it from my example in the answer, however as you use a client (I assume that is your Socket) in your code your probably need to do some mocking for that as well and provide the mock to the method accordingly.
I am trying to use PowerMockito to mock the creation of the java.net.URL class in my code that I'm testing. Basically, I want to prevent the real HTTP request from occurring and instead 1) check the data when the request is made and 2) supply my own test data back on a mocked response. This is what I'm trying:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ URL.class, MockedHttpConnection.class })
public class Test {
URL mockedURL = PowerMockito.mock(URL.class);
MockedHttpConnection mockedConnection = PowerMockito.mock(MockedHttpConnection.class);
...
PowerMockito.whenNew(URL.class).withParameterTypes(String.class).withArguments("MyURLString").thenReturn(mockedURL);
PowerMockito.when(mockedURL.openConnection()).thenReturn(mockedConnection);
...
}
The code that I want to test looks like this:
URL wlInvokeUrl = new URL(wlInvokeUrlString);
connection = (HttpURLConnection) wlInvokeUrl.openConnection();
Earlier in my test scenario I mock the wlInvokeUrlString to match "MyURLString". I've also tried using various other forms of the whenNew line, trying to inject the mock. No matter what I try, it never intercepts the constructor. All I want to do is "catch" the call to openConnection() and have it return my mocked HTTP connection instead of the real one.
I have mocked other classes ahead of this one in the same script and these are working as expected. Either I need a second pair of eyes (probably true) or there is something unique about the URL class. I did notice that if I use "whenNew(URL.class).withAnyArguments()" and change the "thenReturn" to "thenAnswer" I could get it to trigger. Only problem is I never get the URL call for my code. What I see is an invocation of the 3-argument constructor for URL.class with all nulls for the parameters. Could it be this class is from the Java runtime and is bootstrapped by the test runner? Any help is much appreciated.
It's a common mistake when use PowerMockito.whenNew.
Note that you must prepare the class creating the new instance of MyClass for test, not the MyClass itself. E.g. if the class doing new MyClass() is called X then you'd have to do #PrepareForTest(X.class) in order for whenNew to work
From Powermock wiki
So, you need a bit change your test and add to #PrepareForTesta class which create a new instance of URLlike:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ URL.class, MockedHttpConnection.class , ConnectionUser.class})
public class URLTest {
public class URLTest {
private ConnectionUser connectionUser;
#Before
public void setUp() throws Exception {
connectionUser = new ConnectionUser();
}
#Test
public void testName() throws Exception {
URL mockedURL = PowerMockito.mock(URL.class);
MockedHttpConnection mockedConnection = PowerMockito.mock(MockedHttpConnection.class);
PowerMockito.whenNew(URL.class).withParameterTypes(String.class).withArguments("MyURLString").thenReturn(mockedURL);
PowerMockito.when(mockedURL.openConnection()).thenReturn(mockedConnection);
connectionUser.open();
assertEquals(mockedConnection, connectionUser.getConnection());
}
}
where:
public class ConnectionUser {
private String wlInvokeUrlString = "MyURLString";
private HttpURLConnection connection;
public void open() throws IOException {
URL wlInvokeUrl = new URL(wlInvokeUrlString);
connection = (HttpURLConnection) wlInvokeUrl.openConnection();
}
public HttpURLConnection getConnection() {
return connection;
}
}
I'm not sure the difference between .withParameterTypes(x) and .withArguments(x) but I believe you need to set it up as follows for your code to work. Give it a try and let me know if this doesn't help.
PowerMockito.when(mockedURL.openConnection()).thenReturn(mockedConnection);
PowerMockito.whenNew(URL.class).withArguments(Mockito.anyString()).thenReturn(mockedURL);
The problem is that the arguments of the real call are not matching with the expected in your mock.
PowerMockito.whenNew(URL.class).withParameterTypes(String.class).withArguments("MyURLString").thenReturn(mockedURL) will return mockedURL only the call is new URL("MyURLString").
If you change it to:
PowerMockito.whenNew( URL.class ).withParameterTypes( String.class )
.withArguments( org.mockito.Matchers.any( String.class ) ).thenReturn( mockedURL );
It will catch any string passed to the constructor URL(String) (even null) and return your mock.
When you tried
"whenNew(URL.class).withAnyArguments()" and change the "thenReturn" to
"thenAnswer" I could get it to trigger. Only problem is I never get
the URL call for my code. What I see is an invocation of the
3-argument constructor for URL.class with all nulls for the
parameters.
PowerMock will try to mock all constructors (org.powermock.api.mockito.internal.expectation.DelegatingToConstructorsOngoingStubbing.InvokeStubMethod at line 122) then it calls the first one (with 3 arguments) and mock its answer. But the subsequent calls will return the already mocked one because you told it to mock for any arguments. That's why you see just one call with null, null, null in your Answer.
all of the samples i've seen online with regard to custom parametersuppliers have something like:
List<PotentialAssignment> list = new ArrayList<PotentialAssignment>();
list.add(PotentialAssignment.forValue("teams", "giants"));
list.add(PotentialAssignment.forValue("teams", "jets"));
list.add(PotentialAssignment.forValue("teams", "niners"));
return list;
now, the question i have is: what does the first argument to PotentialAssignment.forValue(arg1, arg2) do? Nothing i've seen online has explained the significance of it.
thanks
The first parameter of PotentialAssignment.forValue is the "name" of the value. It is not used, if your #Theory method passes, but if it fails, it is used to assemble the error message. Here is an example:
#RunWith(Theories.class)
public class CustomParameterSupplierTest {
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
#ParametersSuppliedBy(FooSupplier.class)
public #interface Foo {}
public static class FooSupplier extends ParameterSupplier {
#Override
public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
return Arrays.asList(
PotentialAssignment.forValue("one", 1),
PotentialAssignment.forValue("two", 2)
);
}
}
#Theory
public void test(#Foo int foo) {
assertThat(foo, is(1));
}
}
If this test is executed with Junit 4.11 you will get the following error:
org.junit.experimental.theories.internal.ParameterizedAssertionError: test(two)
By the way, in the upcoming release JUnit 4.12 the error reporting is further improved and you will get the following error:
org.junit.experimental.theories.internal.ParameterizedAssertionError: test("2" <from two>)
I wanted to know if there's any way to add test suites dynamically in junit 4.
For example I have a TestClassA as mentioned below having test case "test1"
class TestClassA
{
#Test
public void test1()
{
createTestClassDynamically(); // this creates a test class having
// setUp(), tearDown() methods and one test case .
}
}
Test case test1 has a method createTestClassDynamically() that dynamically creates a new test class (lets say TestClassB) having setUp(), tearDown() methods and one test case (lets say test2()).
I want to run the test1 and then when TestClassB is dynamically generated I want test case "test2" also to be executed.
I know this is quite complicated and not the best thing to do but in my framework I need to do it to generate large number of test classes dynamically rather than having them physically in the package.
Can anyone please provide any help/suggestions?
I have solved this is my framework using the Parameterized feature of Junit 4 which helps to execute same test case with different parameters.
Below mentioned is the sample code on how I acheived it, thought to post it if it helps anyone.
Also, if someone has a better solution, feel free to post it.
class TestClassA
{
private TestClassB classBObj;
public TestClassA(TestClassB obj) {
classBObj= obj;
}
#Test
public void test1()
{
// createTestClassDynamically(); // remove this method as Parameterized
// feature will take care of dynamic test execution.
}
#Test
public void test2()
{
// Test case from Test class B using TestClassB object (classBObj)
}
public static Collection<Object[]> getParameters() {
Collection<Object[]> parameteres = new ArrayList<Object[]>();
Object[] obj1 = new Object[]{new TestClassB()};
Object[] obj2 = new Object[]{new TestClassB()};
parameteres.add(obj1);
parameteres.add(obj2);
// ....... add more test data this way or create a loop
return parameteres;
}
}