I have a class called Menu.java which is used as the interface for my program.
In this Menu.java class, I have a switch/case block which acts as my menu Options.
Basically, I want to use jUnit to test the output of each case in that switch/case block, but I'm struggling to find the best way to do it.
Is it best to have a seperate jUnit TestCase for each menu operation? and then use a single TestUnit to run all cases? Or is there a better way this can be done?
Many thanks.
In general, each class has a corresponding test class. So you would have a MenuTest.java to match your Menu.java. This allows you to find quickly the tests that are associated with a particular file, because of the naming convention.
Then, ideally, each test would have one test method associated with it. So if your switch has 10 cases, you would end up with 10 test methods, one for each case. This allows you to isolate quickly the option that is failing, because you get feedback for each test individually.
Note that TestCase is JUnit 3. If possible, use JUnit 4 tests (org.junit.*), these are annotated with a #Test annotation.
I would use a single test case for each possible work flow. Ideally you would have one assertion per test case, which is probably easier following that guideline. In general you want to keep your unit tests small and concise.
Then I would place all the test cases in the same test class as long as they belong to the same tested class.
I'd create a single class for Menu.java (MenuTest.java). I'd write a test case for each menu option. If you have GUI stuff, separate it from the logic.
No need to test the GUI or its plumbing.
If the method you are testing is receiving different parameters for this switch, consider using a parameterized test case. The advantage is that it's easier to keep track of what need to be changed if your switch changes:
Here is how it works with TestNG (look up "parameterized test case" for JUnit)
// This method will provide data to any test method that declares that
// its Data Provider is named "test1"
#DataProvider(name = "test1")
public Object[][] createData1() {
return new Object[][] {
{ "Foo", new Integer(36) },
{ "Bar", new Integer(37)},
};
}
// This test method declares that its data should be supplied by the
// Data Provider named "test1"
#Test(dataProvider = "test1")
public void verifyData1(String n1, Integer n2) {
System.out.println(n1 + " " + n2);
}
In your case I'd use single test case for all options. You need something like this:
import org.junit.Test;
import org.junit.Assert;
import your.project.Menu;
public class MenuTest {
#Test
public void testCase() {
Menu menu = new Menu();
assertEquals("1",menu.runCase("bar"));
assertEquals("2",menu.runCase("foo"));
//etc
}
}
Related
I have the following method and I wrote a unit test in Java for this method. It is coveraged except from the if statement and I also need to test this part.
#InjectMocks
private ProductServiceImpl productService;
public void demoMethod(final List<UUID> productUuidList) {
if (productUuidList.isEmpty()) {
return;
}
final Map<ProductRequest, PriceOverride> requestMap = getPriceRequests(uuidList);
productService.updateByPriceList(priceRequestMap, companyUuid);
}
However, as the method execution is finalized and does not return anything when uuidList is empty, I cannot test this if block.
So:
How can I test this if block?
Should I create a new Unit Test method for testing this if block? Or should I add related assert lines to the current test method?
Update: Here is my test method:
#Test
public void testDemoMethod() {
final UUID uuid = UUID.randomUUID();
final List<Price> priceList = new ArrayList<>();
final Price price = new Price();
price.setUuid(uuid);
priceList.add(price);
productService.demoMethod(Collections.singletonList(uuid));
}
The general idea is that you don't want to test specific code, but you want to test some behaviour.
So in your case you want to verify that getPriceRequests and priceService.updateByPriceList are not called when passing in an empty List.
How exactly you do that depends on what tools you have available. The easiest way is if you already mock priceService: then just instruct your mocking liberary/framework to verify that updateByPriceList is never called.
The point of doing a return in your if condition is that the rest of the code is not executed. I.e., if this // code omitted for brevity was to be executed, the method would not fill it's purpose. Therefore, just make sure that whatever that code does, it was not done if your list is empty.
You have 3 choices:
Write a unit test with mocks. Mockito allows you to verify() whether some method was invoked.
Write a more high-level test with database. When testing Service Facade Layer this is usually a wiser choice. In this case you can obtain the resulting state of DB in your test to check whether it did what it had to.
Refactor your code to work differently
Check out Test Pyramid and How anemic architecture spoils your tests for more details.
This is my class with main function. Here I initialize a spring bean which has camel route in it. I do not want to test any other classes being referred in this code but I just want to increate code coverage of this main class. How do I mock and test this class?
import org.apache.camel.main.Main;
public class ABC{
public static void main(String[] args) {
Main main = new Main();
MyCamelRoute myCamelRoute = SpringUtil.getBean(MyCamelRoute.class);
main.addRouteBuilder(myCamelRoute);
Thread t = new Thread(() -> {
try {
main.run();
} catch (Exception e) {
_logger.error("Unable to add route", e);
}
}, "started route");
t.start();
}
}
As you're writing of "mocks" I assume you intend to write a unit test.
ONE: Either you test a class or you mock it. You use mocks to make your test independent of the behaviour (and thus possible bugs) of other units (the "dependencies" of your "system under test" (SUT)).
TWO: You do not write tests to increase code coverage. You write tests to enforce requirements of the API contract.
THREE: To test your main method: call it! You can put in arguments and see if the return value matches your expectations.
FOUR: The problem here might be that you've got static dependencies you cannot control. Spring allows you to configure mocks for bean injection. Can't tell you details right now but I am sure you can find out, it should be something like #Configuration annotated classes or test specific versions of them.
But: your test has no control whatsoever over the main object. And sincerely, I would guess that actually you intend to test the Mainclass. Also you might want to inject the Main instance via Spring means.
FIVE: I am not sure wether it is a good idea to involve multi threading in unit tests as it means your test cannot control the environment of your sut. If you do not know where your test starts, you cannot decide if where it ends up is correct or not.
I am currently writing JUnit test cases using the Selenium-RC API. I am writing my scripts like:
//example JUnit test case
public class myScripts extends SeleneseTestCase {
public void setUp() throws Exception {
SeleniumServer newSelServ = new SeleniumServer();
newSelServ.start();
setUp("https://mySite.com", "*firefox");
}
public void insert_Test_Name throws Exception {
//write test code here
}
}
And for each test, I have a new JUnit file. Now, since the beginning of my JUnit files will all basically be the same, just with minor variations towards the end, I was thinking about creating a pre-formatted Java template to write create a file with the redundant code already written. However, I can't find any information on whether this is possible. Does Eclipse allow you to create file templates for certain packages?
Create a super class to add all the common code. Creating template is really bad because of the fact you are duplicating the code at the end of the day.
class Super extends SeleneseTestCase{
// Add all common code
}
class Test1 extends Super{
// only special test case logic
}
Also I would suggest not to create SeleniumServer instance for each test case, It will reduce overall performance of the test suite. You can reuse object as long as you are running test sequentially.
How can I test this method :
public void updateTable() {
try {
String sql = "select * from userDetails";
rs = st.executeQuery(sql);
st = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
table.setModel(DbUtils.resultSetToTableModel(rs));
}
catch(Exception e) {
}
Few suggestions to make this more testable.
updateTable method is doing two things here.
Execute query and get results
Apply the result set to the table.
I would refactor to have two methods.
public ResultSet getResultSetForQuery(String sql,Statement st)
public Table updateTable(ResultSet rs)
Writing tests for the above two methods should be straightforward.
There are so many java libraries available to mock the large data to help testing database related methods. For example Mockito / EasyMock / JMock and more. You can make use of these libraries. You can mock the expected results using the tools and you can test your methods with the expected results.
JUnit: In general, you write a test class like the following and annotate the method(s) that contains you test with #Test. If you want to write a test that has to fail, you can use the 'expected' attribute of the annotation. If you know your test might be running for too long and want it to timeout after a certain period of time, use the 'timeout' attribute in the annotation.
If you have certain logic for initialization before each test method, you put that into another method and annotate that one with #Before. Likewise, to free stuff up, you use #After. For initialization that is to be run once per test class, use the annotation #BeforeClass and make sure that method is public and static - same story with #AfterClass.
In general, in each test method you go like this: Execute some of your code and then make assertions about what you would expect to be the case. In my example, I am testing the method 'myAdd' and I expect that 1+1 adds up to two 2.
public class MyTest {
#Test
public void testAddition() {
int sum = myAdd(1, 1);
assertEquals(2, sum);
}
}
This example is based on JUnit: https://github.com/junit-team/junit/wiki
There are alternatives, like TestNG: http://testng.org/doc/index.html
If you want to test the behaviour of a certain class in relation to its depdencies, a mock framework is recommended. Examples include: jmock, mockito, etc
The two main points of any good test are:
Check that it works well
Localize the error if it's exist
Check that it works well
Localize the error if it's exist
In your case we cannot perform such a good testing to localize the error if it's exist because your method does too complex job. It wold be good to refactor your method into several methods to make it more readable and testable. I agree with #AjayGeorge about the way to separate that method.
And then you can write something like:
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.sql.ResultSet;
public class TestExample {
#BeforeClass
public static void setup() {
// init your connection here
// and insert data for tests
}
#AfterClass
public static void cleanup() {
// close connection
}
#Test
public void testTableUpdate() {
// initialize 'sqlQuery' and 'statement'
ResultSet resultSet = getResultSetForQuery(sqlQuery, statement);
// check 'resultSet' with JUnit methods like assertTrue
updateTable(resultSet);
// check that table is filled as you expected
}
}
The selenium tests I'm gonna be doing are basically based on three main steps, with different parameters. These parameters are passed in from a text file to the test. this allows easy completion of a test such as create three of "X" without writing the code to do the create three times in one test.
Imagine i have a test involving creating two of "X" and one of "Y". CreateX and CreateY are already defined in separate tests. Is there a nice way of calling the code contained in createX and createY from say, Test1?
I tried creating a class with the creates as seperate methods, but got errors on all the selenium.-anything-, ie every damn line. it goes away if i extend seleneseTestCase, but it seems that my other test classes wont import from a class that extends seleneseTestCase. I'm probably doing something idiotic but i might as well ask!
EDIT:
well for example, its gonna be the same setUp method for every test, so id like to only write that once... instead of a few hundred times...
public void ready() throws Exception
{
selenium = new DefaultSelenium("localhost", 4444, "*chrome", "https://localhost:9443/");
selenium.start();
selenium.setSpeed("1000");
selenium.setTimeout("999999");
selenium.windowMaximize();
}
thats gonna be used EVERYWHERE.
its in a class called reuseable. Id like to just call reuseable.ready(); from the tests SetUp... but it wont let me....
public class ExampleTest {
#Before
public void setup() {
System.out.println("setup");
}
public void someSharedFunction() {
System.out.println("shared function");
}
#Test
public void test1() {
System.out.println("test1");
someSharedFunction();
}
#Test
public void test2() {
System.out.println("test2");
someSharedFunction();
}
}
The contents of the function after the #Before annotation is what will be executed before every test. someSharedFunction() is an example of a 'reusable' function. The code above will output the following:
setup
test1
shared function
setup
test2
shared function
I would recommend using JUnit and trying out some of the tutorials on junit.org. The problem you have described can be fixed using the #Before annotation on a method that performs this setup in a super class of your tests