Basically I have this JUnit test for my server here:
#Test
public void test() throws UnknownHostException, IOException, ClassNotFoundException
{
Socket socket = new Socket("localhost", 4444);
PrintWriter stringOut = new PrintWriter(socket.getOutputStream(), true);
ObjectInputStream oIn = new ObjectInputStream(socket.getInputStream());
stringOut.println("getMyString");
String myString = (String) oIn.readObject();
assertEquals("myString", myString);
socket.close();
}
But every time I want to run this test, I need to start the server. How should I get it to start automatically (it has to be in another thread of course)
The technical answer could be to make that socket a field in your test class, and then have a #BeforeAll public static void setUp() method that creates the required object once. Or a #Before public void setUp() that starts the server before every test case. And of course, you would need matching #AfterAll resp. #After methods. As the other answer outlines, you can use a ProcessBuilder for example, to start a completely own process.
But then: a "real" unit test should only rely on your source code. A dependency such as here, that requires an external component/service to be available rather renders these functional or integration tests.
So, the real answer would be: step back. Look at your server code, and ask yourself whether you really need to run the whole server in order to tests its parts.
Meaning: in the end, a "server" is about making some "business logic" available to the outter world. Those are two different concerns, and they should be addressed differently.
So: you write unit tests for your business logic that can all be nicely tested without any server around. And then you write more of an integration test that tests whether your server is correctly "coupled" with the business logic part.
In other words: assume your server offers 3 different services, and each one service has multiple parameters, and "paths" of execution. You absolutely do not test all these services, with all paramater variations and all "paths" by going through your server. Instead, you write your code so that you can test each service completely without spinning up the server for each test. And then, when all of that works, you write a few tests that ensure that each service can be called using the server (and there you focus on very different aspects, like: "are the parameters passed to the service showing up *inside", or "are errors within the business logic processed as expected by the server").
Use ProcessBuilder to start the process, and destroy() to destroy it
ProcessBuilder pb = new ProcessBuilder("/path/to/java", "-jar", "your.jar");
pb.directory(new File("preferred/working/directory"));
Process p = pb.start();
Thread.sleep(1000);
// test here
p.destroy()
Related
I'm working on a simple client-server application, and I'm supposed to initialize my client and server objects in separate threads. The server contains a database of all of the courses in some specific departments at my university, and the GET request gets all of the classes in the requested department and sends it back to the client. While I was able to test everything perfectly fine in a main method, unit testing was just not working. Below is my code for the unit test:
import client.Client;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import server.Server;
public class ClientServerTest {
private static String file = "";
#BeforeClass
public static void setFile(){
file = System.getProperty("file");
}
#Before
public void startServerTest(){
Thread serverThread = new Thread(() -> {
new Server(file);
});
serverThread.start();
}
#Test
public void getTest(){
Client client = new Client();
Assert.assertTrue(client.submitRequest("GET COM"));
Assert.assertTrue(client.submitRequest("GET MAT"));
Assert.assertTrue(client.submitRequest("GET BIO"))
}
}
When I run the test, the server test passes, I get the following output for the getTest() test:
java.net.ConnectException: Connection refused: connect
I've been looking around trying to find the best way to get unit tests to work with threads, but I can't seem to figure it out. Any help would be most appreciated.
First, as my fellows stated, that's far away from a unit test but an integration or end-to-end test.
The problem with your test might be that some threads outperforms other threads creating randomly failing tests so you need some option to synchronize them.
I can say that it's absolutely possible to do this kind of testing with JUnit but there are some key concepts to put into practice to make such tests, involving multiple threads, reproducible (not flaky) and any useful.
Without seeing the implementation of Server class it's pretty difficult but I try to sum up the hints that hopefully put you on the right track.
First:
Create your Server class and all other dependencies inside the same thread (preferably in the main thread).
public static void main(String[] args) {
Foo otherInstance = new Foo(...);
Bar anotherInstance = new BarImpl(otherInstance,...);
Server server = new Server(otherInstance, anotherInstance);
server.start(); // blocking until app is stopped in a graceful way and where real application logic starts
// not more to do here
}
Important is that constructors must not do any "work" apart from assigning instance variables like this.someVar = someVar. The concept behind that is called dependency injection and makes your life a lot easier especially if you use a library.
Second:
Your app needs hooks, that tests can plug into to intercept your logic, where you can make threads halt and wait for other events happen that are necessary to make your tests work. Where to plug into depends highly on your application. It's most likely necessary to specify different implementations for some classes inside your tests thus differently wiring the app's dependency graph.
To accomplish that synchronizations aids like CountDownLatch are your best friends inside the test class.
#Test
public void someTest() {
// or move the instantiation logic to the #Before setup method
final CountDownLatch isConnected = new CountDownLatch(1);
Foo otherInstance = new Foo(...);
Bar anotherInstance = new BarTestImpl(otherInstance,...);
// here we plug into the connected event
anotherInstance.setConnectionListener(() -> { isConnected.countDown(); }
Server server = new Server(otherInstance, anotherInstance);
server.startAsync(); // not blocking
...
// test logic starting, do some assertions or other stuff
...
// block until connected event is received
isConnected.await(1, TimeUnit.SECONDS);
// do some assertions
assertTrue(server.isConnected());
...
}
This example is scratching on the surface of what is possible and how to leverage this concept for maintaining a high level of automated testing but it should show the idea behind.
Normally a UnitTest should only test a single component. The "Unit".
You whant to do some kind of integration testing. So you have to ensure that every component that you need for your #Test is up an running before #Test is called.
I'm not sure if JUnit is the best framework for this. But you can add a check in the #Before method that will sleep the main thread until the server is running.
For example:
#Before
public void startServerTest(){
Server = new Server();
Thread serverThread = new Thread(() -> {
server.init(file);
});
serverThread.start();
while (!server.isRunning() {
Thread.sleep(1000);
}
}
I am writing camel unit test. One service that I interface with is Solr. After testing with mocks, I want to write tests that bring up a local solr instance.
So far I have tried to leverage the RestTestBase Solr class (org.apache.solr.util.RestTestBase). Because I am writing a unit test, I have not extended the class, merely tried to use the static methods it provides. The following does not work:
RestTestBase.createJettyAndHarness("src/test/resources/solr",
"solrconfig.xml", "schema.xml",
"/solr", true, null);
int solrPort = RestTestBase.jetty.getLocalPort();
String solrURL = "localhost:"+Integer.toString(solrPort)+"/solr";
...
I included solr and jetty in my pom. Any suggestions for how to programmatic stand up and shut down a solr instance? (because i am using camel unit testing, i prefer not to extend RestTestBase)
see the camel-solr unit tests for some complete examples....SolrComponentTestSupport
basically this...
#BeforeClass
public static void beforeClass() throws Exception {
// Set appropriate paths for Solr to use.
System.setProperty("solr.solr.home", "src/test/resources/solr");
System.setProperty("solr.data.dir", "target/test-classes/solr/data");
// Instruct Solr to keep the index in memory, for faster testing.
System.setProperty("solr.directoryFactory", "solr.RAMDirectoryFactory");
// Start a Solr instance.
solrRunner = new JettySolrRunner("src/test/resources/solr", "/solr", getPort());
solrRunner.start();
solrServer = new HttpSolrServer("http://localhost:" + getPort() + "/solr");
}
#AfterClass
public static void afterClass() throws Exception {
if (solrRunner != null) {
solrRunner.stop();
}
}
I want to continue test run execution even the one or more assertions get fails in TestNG.
I referred below links in order to implement soft assertion in my project.
http://beust.com/weblog/2012/07/29/reinventing-assertions/
http://seleniumexamples.com/blog/guide/using-soft-assertions-in-testng/
http://www.seleniumtests.com/2008/09/soft-assertion-is-check-which-doesnt.html
But I'm not understanding the flow of code execution, like function calls, FLOW.
Kindly help me to understand the work flow of the soft assertions.
Code:
import org.testng.asserts.Assertion;
import org.testng.asserts.IAssert;
//Implementation Of Soft Assertion
public class SoftAssertions extends Assertion{
#Override public void executeAssert(IAssert a){
try{ a.doAssert(); }
catch(AssertionError ex){
System.out.println(a.getMessage()); } } }
//Calling Soft Assertion
SoftAssertions sa = new SoftAssertions();
sa.assertTrue(actualTitle.equals(expectedTitle),
"Login Success, But Uname and Pwd are wrong");
Note:
Execution Continues even though above assertion fails
Soft assertions work by storing the failure in local state (maybe logging them to stderr as they are encountered). When the test is finished it needs to check for any stored failures and, if any were encountered, fail the entire test at that point.
I believe what the maintainer of TestNG had in mind was a call to myAssertion.assertAll() at the end of the test which will run Assert.fail() and make the test fail if any previous soft-assertion checks failed.
You can make this happen yourself by adding a #Before method to initialize your local soft-assertion object, use it in your test and add an #After method to run the assertAll() method on your soft-assertion object.
Be aware that this #Before/#After approach makes your test non-thread-safe so each test must be run within a new instance of your test class. Creating your soft-assertion object inside the test method itself and running the assertAll() check at the end of the method is preferable if your test needs to be thread-safe. One of the cool features of TestNG is its ability to run multi-threaded tests, so be aware of that as you implement these soft-asserts.
We all know what the code below does
class Demo{
public static void main(String b[]){
System.out.println("Argument one = "+b[0]);
System.out.println("Argument two = "+b[1]);
}
}
My question (infact curiosity) is, if this application is a daemon that is running and java based server waiting for clients to do socket stuff with it, can I run the application again, and pass new parameters to it ? Basically I am looking at not implementing a cli kinda thing. I need it simple.
Edit : I want to change / add more parameters at runtime. But if I run the app with new parameters, wont it start another instance ?
No, you can't modify the arguments passed after the application started.
The array used to retreive the parameters is populated when it starts and cannot be altered.
If the application is a server, you should be able to implement a CLI rather easily with a simple thread waiting for input.
Seems like you have an existing application that is being run as a command line application right now. It is being invoked as and when required from command line passing the appropriate command line parameters. And now what you would like to do is host this same application as a daemon service which gets invoked as and when the parameters come over a port it is listening to.
Assuming your goal is the above and for whatever reason you want to retain the above main() signature, the key is to realize that the main() method is also like any other static method which can be invoked by a class reference. So the following is possible:
class SocketListener extends Thread {
public void run() {
// Code for listening to socket that calls invokeDemo()
// method below once it detects the appropriate args.
}
private void invokeDemo(String[] args) {
// You can invoke the main method as any other static method.
Demo.main(args);
}
}
This would just treat Demo class as part of a library it is using and not launch any other application. If you do want to launch it as an application (because of some special reason), you would need to use the Process and Runtime classes of java.
I am attempting to run a JUnit Test from a Java Class with:
JUnitCore core = new JUnitCore();
core.addListener(new RunListener());
core.run(classToRun);
Problem is my JUnit test requires a database connection that is currently hardcoded in the JUnit test itself.
What I am looking for is a way to run the JUnit test programmatically(above) but pass a database connection to it that I create in my Java Class that runs the test, and not hardcoded within the JUnit class.
Basically something like
JUnitCore core = new JUnitCore();
core.addListener(new RunListener());
core.addParameters(java.sql.Connection);
core.run(classToRun);
Then within the classToRun:
#Test
Public void Test1(Connection dbConnection){
Statement st = dbConnection.createStatement();
ResultSet rs = st.executeQuery("select total from dual");
rs.next();
String myTotal = rs.getString("TOTAL");
//btw my tests are selenium testcases:)
selenium.isTextPresent(myTotal);
}
I know about The #Parameters, but it doesn't seem applicable here as it is more for running the same test case multiple times with differing values. I want all of my test cases to share a database connection that I pass in through a configuration file to my java client that then runs those test cases (also passed in through the configuration file).
Is this possible?
P.S. I understand this seems like an odd way of doing things.
You can use java system properties to achieve this.
Simply pass what you need with -Dconnectionstring=foobar in the junit command line, or use the java api for system properties to set this programmatically, with System.setProperty(String name, String value), and System.getProperty(String name).
In your tests, you can use the #Before or #BeforeClass to set up common objects based on this property, pending on whether you want to run the setup once for each test (in which case you can use class members) or once for each suite (and then use static members).
You can even factorize this behavior by using an abstract class which all your test cases extends.