Can you run JUnit Tests for a CLI application? - java

I am relatively new to unit tests in Java and I made an application completely with CLI. Example once starting the application the user is given a set of options like so.
Register
Login
.
.
. Etc etc.
If he choses to login he is transferred to a Register () method that asks for details such as name and surname inside the method itself.
I want to know if there is any way lf simulating user input when creating the unit tests or if I have to override the methods so that I can pass values through the arguments and do unit testing that way.

Ideally your code should be written so that it's easy to test, and the method of input doesn't matter. This means that the input should be separated from the business logic, so that when you're writing the tests, you can ignore the input part completely.
For example instead of having a global Scanner and having something like the following, which makes the method dependent on the input method
public void login() {
String username = scanner.nextLine();
// check that the username is valid
}
a more testable method without any dependencies to the input method would be
public void login(String username) {
// check that the username is valid
}
also make sure you understand what constitutes a correct unit test. For this method the obvious tests would be that you can login with valid credentials, and that you can't login with invalid credentials.

Related

Junit test cases for StreamSupport

I am new to test cases I tried several ways to write test case for below piece of code but I never succeeded. How to write junit test case for below code using Powermockito?
StreamSupport.stream(irSet.spliterator(), false)
.filter(iResultRow -> iResultRow !=null)
.mapToInt(iResultRow ->{
String event = iResultRow.get("STF_TY_GH");
return StringUtils.isNotBlank(event) ? Integer.parseInt(event) : 1;
}).findFirst().orElse(1);
While, using a descent amount of mocks you can mock every single call, let me suggest you an alternative approach.
So you have a stream produced out of some input set (irSet) variable. This stream makes "some" processing and returns an integer result.
So if you "imagine" Its a black box: a kind of function that looks like this:
int doSomething(Set<SomeRow> irSet) {
... your implementation is here...
}
In this case, you might want to test what it does by supplying the various input sets and expecting for some outputs. What if there are null-s in the input? Will it fail or filter out what's needed. What if the set is empty? What if there is SomeRow that really has STF_TY_GH data, what if the set doesn't have such a row?
Here is a test for example:
#Test
public void test_rows_with_null_are_processed_correctly() {
// setup:
Set<SomeRow> input = ...// prepare a set with null values
// when:
Integer actual = underTest.doSomething(input)
// then:
// verify this "actual" whether it should be 1 or something else
}
All-in-all, use mocks only for interactions (with something you can't really instantiate like DB API/remote HTTP calls) or for something that is not related to the tested code and is used as a dependency the tested code interacts with. After all, the goal of unit tests is to test your code (the implementation of doSomething in this case and not to mock everything out).

How to perform Junit tests without affecting real data?

I am currently been assigned to creating Junit tests for a project. I created some test, however after reading up on some best practices I discovered that Junit tests should not affect real data as it can comprise integrity of the data.
One test for example below tests the Editing of an existing user's data in the repository:
#Test
void EditUserTest()
{
UserController userController = new UserController();
List<User> userList = (List<User>) userController.getCurrentUserlist();
RoleController roleController = new RoleController();
List<Role> roleList = (List<Role>) roleController.GetCurrentRolelist();
User selectedUser = userList.get(0);
selectedUser.setLoginName("EditedLoginName");
selectedUser.setFirstName("EditedFirstName");
selectedUser.setLastName("EditedLastName");
selectedUser.setEmployeeID(555555555);
selectedUser.setRole(roleList.get(6));
selectedUser.setAutoLogoutPeriod(6);
selectedUser.setEksSerial("45f869");
selectedUser.setEksLevel(9);
User NonExistent = new User();
assertTrue(userController.EditUser(selectedUser), "Testing edit to User in repository");
assertFalse(userController.EditUser(NonExistent), "Testing edit to Non-Existent User in repository");
User editedUser = userController.GetUser(selectedUser.getID());
assertEquals("EditedLoginName", editedUser.getLoginName(), "Testing edit to User Login name");
assertEquals("EditedFirstName", editedUser.getFirstName(), "Testing edit to User First name");
assertEquals("EditedLastName", editedUser.getLastName(), "Testing edit to User Last name");
assertEquals(55555555, editedUser.getEmployeeID(), "Testing edit to User Employee ID");
assertEquals(roleList.get(6), editedUser.getRole(), "Testing edit to User Role");
assertEquals("45f869", editedUser.getEksSerial(), "Testing edit to User Eks Serial");
assertEquals(9, editedUser.getEksLevel(), "Testing edit to User Eks Level");
}
As you can see I retrieve a list of the current users within the repository and just take the first one. After changing its values I then make the actual edit to the repository using the controller and later retrieve the same user from the repository to compare and see if an edit was actually made. Now how would I test this same thing without actually affecting the real data within the repository?
Unit tests are not supposed to access real data. You need to mock any such data so that the real data is not affected.
The purpose of unit tests is to test the functionality, it isn't dependent on the real data.
You can look into Mockito for mocking objects that exhibit the behavior of actual objects.
This link might be helpful: Official docs
If you are writing unit tests then your tests should only focus on the components you are testing, which means if you are testing controller layer you should not call service or dao layer and use their functionalities.
Let's say you want to test your controller then, you should mock the service layer using Mockito or any other test framework. By mocking you are basically avoiding actual service call and continue with your controller level testing.
This example will help

unittest - junit and Mockito. Test addNewAccount to Databases, f I need to remove/delete a account

I have written to Unit test - junit with Mockito library to test any methods, who save to databases new account - addNewAccount methods.
I would like to ask - if I need to add a method or what and how - to delete/remove an account, whos was added. and please show me what I can do it.
my unit test is:
#Test
public void shouldSaveaAccountToDb() {
Account acc = new Account();
acc.setUser(this.user);
acc.setEmail(this.mail);
String account = this.accountController.addNewAccount(this.user, this.mail);
verify(this.accountRepepetytory)).save(Mockito.refEq(acc, new String[0]));
Assert.assertThat(account, CoreMatchers.is("Account"));
}
I also want to add a case with a null value and testing null and empty string. if you can any idea to add test case please tell me.
thank you very match for help. I improved my test.
I have also a method who testing with null value. This is the method.
#Test
public void SaveToDatabaseWithNull() {
Account acc = new Account();
String mail = null;
user.setMail((String)mail);
user.setUser(this.user);
String account = this.accountController.addNewAccount(this.user, (String)mail);
verify(this.accountRepetytory)).save(Mockito.refEq(uaccount, new String[0]));
Assert.assertThataccountCoreMatchers.is("Account"));
}
I also would like to ask, whether in these tests it is necessary to delete some values, adding a method that deletes the account. if I create an account in one method, do I have to delete it in some way and in which way? to test correctly with the null value in the later method.
In your code you have some weaknesses that make you test britle and hard to understand:
Each test method should verify one single expectation only.
Your test verifies two things:
The code created an object of class Account that equals to the one created in the test method by the means of the Account classes implementation of equals().
The return value of the method is a string with content "Account".
Problem of that is that the test does not explain why you expect that string.
So basically you should have separate methods to verify either behavior allowing for a better description of the tested behavior in the test method name.
reduce dependencies to unrelated code.
Mockito.refEq() relies on a (correct) implementation of the equals method in class Account. There is no quaratee that this method is actually implemented or (even worse) may need addioional configuration in future if an account gets more properties that are not allowed to be null.
The better way here is to use an ArgumentCaptor and verify the properties of the captures object:
#Test
public void shouldPassAnAccountObjectWithNameAndEmailSetToDB() {
ArgumentCaptor<Account> accountCaptor =
ArgumentCaptor.forClass(
Account.class);
this.accountController.addNewAccount(
this.user,
this.mail);
verify(this.accountRepepetytory))
.save(
accountCaptor.capture());
Assert.assertThat(
"user",
accountCaptor.getValue().getUser(),
CoreMatchers.is(this.user));
Assert.assertThat(
"email",
accountCaptor.getValue().getEmail(),
CoreMatchers.is(this.email));
}

Spring security authrorize based on input parameter criteria

I have a scenario where I need to authorize user based on combination of his permission and input parameter passed.
this is the current scenario
public void bookTicket(String bookingType)
{
if (bookingType == "AIR"){
bookAirTicket();
}else{
bookBusTicket();
}
}
#PreAuthorize("hasRole('BOOK_AIR')")
private void bookAirTicket(){
}
#PreAuthorize("hasRole('BOOK_BUS')")
private void bookBusTicket(){
}
Can we have some thing like
#PreAuthorize(("hasRole('BOOK_AIR')" AND bookinType='AIR') OR ("hasRole('BOOK_BUS')" AND bookinType='BUS'))
public void bookTicket(String bookingType)
{
if (bookingType == "AIR"){
bookAirTicket();
}else{
bookBusTicket();
}
}
Basically I need authorization based in input parameters
Thanks
Yes, you can. Parameters can be accessed as Spring EL variables. In fact the reference manual gives several examples which use method parameters. The class needs to be compiled with debug symbols present (which is usually the case).
Note that the annotation value is a single expressions string:
"(hasRole('BOOK_AIR') and #bookinType == 'AIR') or (hasRole('BOOK_BUS') and #bookinType='BUS')"
In practice, using complicated expressions is rather error-prone. You could also use a simpler expression, something like
"#accessChecker.check('book', #bookinType)"
Where accessChecker is a bean in your application context with a "check" method which returns true or false depending on whether the supplied operation information is allowed (you can check the current user's roles by accessing the security context yourself - you'll find that discussed elsewhere on SO).
You could also look into writing your own AccessDecisionManager or AccessDecisionVoter and plugin the functionality there, but that requires more internal knowledge.

Play! Framework - SaaS subdomain name filter

I know this question has been asked quite a few times, however, I have a different approach of what I want to achieve.
Since Play 1.1, you're able to match hosts. This is very useful, however, it means that for every controller, I will need to pass through the subdomain route param. This is quite a burden and repeatful if I have hundreds of controllers which use the subdomain param.
Is there not a way to create a filter which looks at the host name before everything else is executed and then sets an on-the-fly config value for that request?
For example (brainstorming), a filter would do the following:
// use request host, but hard-coded for now...
String host = "test.example.com";
Pattern p = Pattern.compile("^([a-z0-9]+)\\.example\\.com$");
Matcher m = p.matcher(host);
if (m.matches()) {
// OUT: test
System.out.println(m.group(1));
System.setProperty("host", m.group(1));
}
And in the models I'd do something like System.getProperty("host");
I know this isn't how it should be done, but I'm just brainstorming.
At least with this way:
I don't have to pass the subdomain param through to every
controller.
I don't have to pass the subdomain param through to any models
either
Models have direct access to the subdomain value so I can filter out objects that belong to the client
Also, I'm aware that System.setProperty() always applies to the entire JVM; which is a problem. I only want this value to be available throughout the duration of the request. What should I use?
Let's analyse. How would you do it? What would be a good approach? Is this possible with Play? I'm sure there are quite a few running into this problem. Your input is highly appreciated.
I think you are close. If I had to do this, I would write a controller annotated with #Before and have that method extract the hostname from the request headers and put it in renderArgs.
Something like this (I haven't tested it):
public class HostExtractor extends Controller {
#Before
public static void extractHost() {
// Code to read from request headers and extract whatever you need here.
String host = 'Your Code Here'
renderArgs.put("hostname", host);
}
}
Then, in your other controllers, you tell it you want to use that controller above as a filter.
#With(HostExtractor.class)
public class MyController extends Controller {
public static void homepage() {
String hostname = renderArgs.get("host", String.class);
// Do whatever logic you need to render the page here.
}
}
Again, I haven't tested this, but I'm doing something similar to cache objects in memcache. I hope that helps!

Categories