I'm trying to perform unit testing and write a test for jdbctemplate.query. I need the code coverage for the below method.
Code:
` public List<User> UserInfo(final Long runId){
jdbcTemplate.setFetchSize(10);
List<User> userList = jdbcTemplate.query(con -> con.prepareStatement(GET_USER_INFO)
, (rs, rowNum) -> {
String userName = rs.getString("username");
String shoppingItems = rs.getString("shopingItems");
Long shoppingid = rs.getLong("shoppingid");
User user= new User();
user.setCmts(userName);
user.setNodeid(shoppingItems);
user.setNodename(shoppingid);
user.setRunId(runId);
return user;
});
return userList;
}`
I have written the test as below, but running the test "coverage as junit" doesn't show me any code coverage for method which is inside the (rs, rowNum) -> {
Test:
`#InjectMocks
private OracleRepository oracleRepository;
#Mock
private JdbcTemplate jdbcTemplate;
#Mock
private ResultSet rs;
#Mock
private Connection connection;
#Mock
private PreparedStatement stmt;
#Mock
private RowMapper rowMapper;
#Test
public void UserInfoTest() throws SQLException {
String username= "joe";
String shoppingItems= "3";
long shoppingId = 1123456778;
long runId = 2;
List<User> listUser = new ArrayList<User>();
Mockito.when(rs.getString("cmts")).thenReturn(cmts);
Mockito.when(rs.getString("node")).thenReturn(node);
Mockito.when(rs.getLong("nodeid")).thenReturn(nodeid);
User user= new User();
user.setUserName(username);
user.setShoppingItems(shoppingItems);
user.setShoppingId(shoppingId);
user.setRunId(runId);
listUser.add(user);
Mockito.when(connection.prepareStatement(Mockito.any(String.class))).thenReturn(stmt);
Mockito.when(rowMapper.mapRow(Mockito.any(ResultSet.class), Mockito.any(Integer.class))).thenReturn(user);
Mockito.when(jdbcTemplate.query(Mockito.anyString(), Mockito.any(RowMapper.class))).thenReturn(listUser);
List<User> list = oracleRepository.UserInfo(runId);
}`
How do I solve this problem?
At the bottom of your test after the List<User> you can add:
ArgumentCaptor<RowMapper> argCaptor = ArgumentCaptor.forClass(RowMapper.class);
Mockito.verify(jdbcTemplate).query(Mockito.any(PreparedStatementCreator.class), argCaptor.capture());
RowMapper<User> rowMapper = argCaptor.getValue();
User userResult = rowMapper.mapRow(rs, -1);
verify(rs).getString("username");
verify(rs).getString("shopingItems");
verify(rs).getLong("shoppingid2");
assertEqual(cmts, userResult.getCmts());
This captures the functional interface you defined, then you call it as the action to test it. I checked the verifies and assertion also. However, this is not the easiest to understand if anyone else ever has to maintain this codebase. You might want to consider creating a class that implements the interface and test that directly for readability.
Related
I've followed an open Course on Spring web. Written some code to list all orders from a database and return them through a rest api. This works perfectly. Now I'm writing some code to give the ID of the order in the request, find 0 or 1 orders and return them. However, when there is no Order find with the given ID, a nullpointerexception is given. I can't find out what is causing this. I'm assuming the .orElse(null) statement. Please advise
Controller:
#RequestMapping("api/V1/order")
#RestController
public class OrderController {
private final OrderService orderService;
#Autowired
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
#GetMapping(path = "{id}")
public Order getOrderById(#PathVariable("id") int id) {
return orderService.getOrderById(id)
.orElse(null);
}
}
Service:
#Service
public class OrderService {
private final OrderDao orderDao;
#Autowired
public OrderService(#Qualifier("oracle") OrderDao orderDao) {
this.orderDao = orderDao;
}
public Optional<Order> getOrderById(int orderNumber) {
return orderDao.selectOrderById(orderNumber);
}
}
Dao:
#Override
public Optional<Order> selectOrderById(int searchedOrderNumber) {
final String sql = "SELECT \"order\", sender, receiver, patient, orderdate, duedate, paymentref, status, netprice from \"ORDER\" where \"order\" = ?";
Order order = jdbcTemplate.queryForObject(sql, new Object[] {searchedOrderNumber}, (resultSet, i) -> {
int orderNumber = resultSet.getInt( "\"order\"");
String sender = resultSet.getString("sender");
String receiver = resultSet.getString("receiver");
String patient = resultSet.getString("patient");
String orderDate = resultSet.getString("orderdate");
String dueDate = resultSet.getString("duedate");
String paymentRef = resultSet.getString("paymentref");
String status = resultSet.getString("status");
int netPrice = resultSet.getInt("netprice");
return new Order(orderNumber,sender,receiver,patient,orderDate,dueDate,paymentRef,status,netPrice);
});
return Optional.ofNullable(order);
}
For the Jdbcexception, use general query instead of the queryForObject, or use try/catch to convert the Jdbc related exception, else Spring itself will handle these internally using ExceptionTranslater, ExceptionHandler etc.
To handle optional case in controllers, just throw an exception there, for example PostController.java#L63
And handle it in the PostExceptionHandler.
Editing based on comment about stack trace
For your error please check - Jdbctemplate query for string: EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0
To solve problem associated with orderService.getOrderById(id) returning null you can return ResponseEntity.ResponseEntity gives you more flexibility in terms of status code and header. If you can change your code to return ResponseEntitythen you can do something like
#GetMapping(path = "{id}")
public ResponseEntity<?> getOrderById(#PathVariable("id") int id) {
return orderService
.getOrderById(id)
.map(order -> new ResponseEntity<>(order.getId(), HttpStatus.OK))
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
You can even write generic Exception handler using #ControllerAdvice and throw OrderNotFoundException as .orElse(throw new OrderNotFoundException);. Check more information here.
I have such question. I'm using DBsetup for spring boot tests and postgresql database. And I'm using DBsetup to set user, but when I'm trying to set another user by spring data I have the next exception:
Подробности: Key (id)=(1) already exists.
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [users_pkey];
This is my test class:
#RunWith(SpringRunner.class)
#SpringBootTest
#TestPropertySource("/application-test.properties")
public class UserRepositoryTest {
#Autowired
private ApplicationContext applicationContext;
#Autowired
private UserRepository userRepository;
#Autowired
private DataSource dataSource;
#Before
public void insertData() throws SQLException {
Operation operation = sequenceOf(CommonOperations.DELETE_ALL, CommonOperations.INSERT_USER);
DbSetup dbSetup = new DbSetup(new DataSourceDestination(dataSource), operation);
dbSetup.launch();
}
#After
public void cleanPK() throws SQLException {
DBUtil.resetAutoIncrementColumns(applicationContext, "user");
}
#Test
public void registerUser() {
val user = new User(null, "Glass", "123123", "glass999#mail.ru");
assertEquals(user, userRepository.saveAndFlush(user));
}
}
Operations for DBsetup:
public class CommonOperations {
public static final Operation DELETE_ALL = deleteAllFrom("article_tag", "article", "tag", "users");
public static final Operation INSERT_USER =
insertInto("users")
.columns("id", "email", "password", "username")
.values(1, "krikkk998#mail.ru", "123123", "Daimon")
.build();
}
Class to reset sequence:
#NoArgsConstructor
public final class DBUtil {
public static void resetAutoIncrementColumns(ApplicationContext applicationContext,
String... tableNames) throws SQLException {
DataSource dataSource = applicationContext.getBean(DataSource.class);
String resetSqlTemplate = "ALTER SEQUENCE %s RESTART WITH 1;";
try (Connection dbConnection = dataSource.getConnection()) {
for (String resetSqlArgument: tableNames) {
try (Statement statement = dbConnection.createStatement()) {
String resetSql = String.format(resetSqlTemplate, resetSqlArgument + "_id_seq");
statement.execute(resetSql);
}
}
}
}
}
Does anyone know how to solve this problem?
One thing to look at:
public static final Operation INSERT_USER =
insertInto("users")
.columns("id", "email", "password", "username")
.values(1, "krikkk998#mail.ru", "123123", "Daimon")
.build();
Here you are using a hard-coded id i.e. 1
Now, when in the test case you are trying to create another user, you passed the id as null, assuming it's supposed to pick from the sequence. It will start from 1 too. Hence, you get a conflict.
You have an issue related to constraint violation. So one thing you can do is in your table change the 'id' column to "auto_increment". The DB will take care of incrementing this column value automatically.
At any point, if you want to reset this id value, you can call "resetAutoIncrementColumns()", and then in your INSERT SQL, you do not have to specify the 'id' column at all. It will always insert a unique value when a new user is saved.
Hope this will help you.
How can we write mockito for the below code? It's been written in normal JDBC. I need to create a mock of all this code having main method (which is driving all the logic of updating the data).
I am really need help in mocking the avoid inserting the actual data. Could someone please guide me ?
public class PaytPaytmBilling {
private static Category logger = Category.getInstance(PaytPaytmBilling.class);
private static InputStream inputS = XY.class.getResourceAsStream("/paytm.properties");
private static final INSERT_QUERY = "INSERT STATEMENT";
private static void insertPaytPaytmBilling(ArrayList allPaytPaytmBill) throws Exception{
conn = getConnection(userId, passwd, prop.getProperty("databaseURL"));
String childSql = buildInsertPaytPaytmBillSql();
PreparedStatement pStatement = conn.prepareStatement(childSql);
for (int i=0; i<allPaytPaytmBill.size(); i++){
PaytPaytmBill PaytmBill = (PaytPaytmBill) allPaytPaytmBill.get(i);
pStatement.setString(1, PaytmBill.getXX());
pStatement.setString(2, PaytmBill.getYY());
pStatement.setString(3, PaytmBill.getAA());
pStatement.setLong(4, PaytmBill.getBB());
pStatement.setLong(5, PaytmBill.getCC));
pStatement.setString(6, PaytmBill.getDD());
pStatement.setInt(7, PaytmBill.getEE());
pStatement.setInt(8, PaytmBill.getFF());
pStatement.setString(9, "");
pStatement.setString(10, "");
pStatement.execute();
}
pStatement.close();
conn.close();
}
private static void getDbConn() throws Exception {
// Here get DB connection
}
public static void main(String[] args) throws Exception
{
ArrayList allPaytPaytmBill = new ArrayList();
XY.init();
getDbConn();
// This query reads data from other tables and creates the data..
String qmrString = qmr.buildQmrSql();
allPaytPaytmBill = qmr.getAllMemberData(qmrString);
insertPaytPaytmBilling(allPaytPaytmBill);
}
}
Mockito Test class:
#RunWith(MockitoJUnitRunner.class)
public class PaytmBillingTest {
private static Category logger = Category.getInstance(PaytmBillingTest.class);
#Mock
private DataSource ds;
#Mock
private Connection c;
#Mock
private PreparedStatement stmt;
#Mock
private ResultSet rs;
private ArrayList<PaytmBill> allPaytmBill;
#Before
public void before() {
allPaytmBill = new ArrayList<>();
PaytmBill PaytmBill = new PaytmBill();
PaytmBill.setAA("1182");
PaytmBill.setBB("5122");
PaytmBill.setCC("201807");
PaytmBill.setDD(0L);
PaytmBill.setEE(100);
PaytmBill.setFF(0);
PaytmBill.setGG(0);
PaytmBill.setHH("A");
PaytmBill.setII(null);
PaytmBill.setJJ(null);
allPaytmBill.add(PaytmBill);
}
#Test
public void testPaytmBilling() {
PaytmBilling PaytmBilling = new PaytmBilling();
}
}
First of all, it looks like you are not showing use the real code. For example you added private static void getDbConn() but the code calls conn = getConnection(...), the variable conn is not declared anywhere, etc. This makes it harder to really help with your issue.
Looking at your unit test, you want to mock instances of certain classes used by PaytPaytmBilling, like DataSource, Connection and PreparedStatement. These are called 'dependencies'.
In order to do that, you need to change PaytPaytmBilling so that these dependencies are 'injected' (see Dependency Injection). This means they are provided to PaytPaytmBilling via the constructor or a setter (or with some frameworks just by adding an annotation on the field).
In the current code, the dependencies are obtained by PaytPaytmBilling itself (e.g. by calling a static method, or creating a new instance) and they cannot be mocked (except via some black magic mocking frameworks which I don't advise you to get into right now).
To write good unit tests, you need to write (or refactor) the code to be testable, which means dependencies are injected, not obtained internally in the class. Also avoid static methods and data (constants are ok), they don't play nice with dependency injection and testable code.
So for example the DataSource could be injected via the constructor like this:
public class PaytPaytmBilling {
private static final String CHILD_SQL = "SELECT bladiebla...";
private DataSource dataSource;
public PaytPaytmBilling(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insertPaytPaytmBilling(List<PaytmBill> allPaytPaytmBill) {
// keeping the example simple here.
// don't use String literals for the parameters below but read
// them from Properties (which you can mock for the unit test)
Connection conn = dataSource.getConnection("userId", "passwd", "url");
PreparedStatement pStatement = conn.prepareStatement(CHILD_SQL);
for (int i=0; i<allPaytPaytmBill.size(); i++){
PaytPaytmBill PaytmBill = (PaytPaytmBill) allPaytPaytmBill.get(i);
pStatement.setString(1, PaytmBill.getXX());
pStatement.setString(2, PaytmBill.getYY());
pStatement.setString(3, PaytmBill.getAA());
// ...
pStatement.execute();
}
pStatement.close();
conn.close();
}
If you re-write the code like above, you could test it like this:
#RunWith(MockitoJUnitRunner.class)
public class PaytmBillingTest {
// this will cause Mockito to automatically create an instance
// and inject any mocks needed
#InjectMocks
private PaytmBilling instanceUnderTest;
#Mock
private DataSource dataSource;
// connection is not directly injected. It is obtained by calling
// the injected dataSource
#Mock
private Connection connection;
// preparedStatement is not directly injected. It is obtained by
// calling the connection, which was obtained by calling the
// injected dataSource
#Mock
private PreparedStatement preparedStatement;
private List<PaytmBill> allPaytmBill;
#Before
public void before() {
allPaytmBill = new ArrayList<>();
PaytmBill paytmBill = new PaytmBill();
paytmBill.setAA("1182");
paytmBill.setBB("5122");
paytmBill.setCC("201807");
paytmBill.setDD(0L);
paytmBill.setEE(100);
paytmBill.setFF(0);
paytmBill.setGG(0);
paytmBill.setHH("A");
paytmBill.setII(null);
paytmBill.setJJ(null);
allPaytmBill.add(PaytmBill);
}
#Test
public void testPaytmBilling() {
// given
when(dataSource.getConnection(anyString(), anyString(), anyString())).thenReturn(connection);
when(connection.prepareStatement(anyString())).thenReturn(preparedStatement);
// when
instanceUnderTest.insertPaytPaytmBilling(allPaytPaytmBill);
// then
verify(pStatement).setString(1, paytmBill.getXX());
verify(pStatement).setString(2, paytmBill.getYY());
verify(pStatement).setString(3, paytmBill.getAA());
// ...
verify(pStatement).execute();
verify(pStatement).close();
verify(connection).close();
}
Unrelated suggestion regarding your code: It's better to close resources in a finally block, or using try-with resources. In you current code resources will not be closed if an exception occurs whilst processing on the resources:
Connection conn = dataSource.getConnection("userId", "passwd", "url");
PreparedStatement pStatement = conn.prepareStatement(childSql);
try {
// processing steps
}
finally {
pStatement.close();
conn.close();
}
Or try-with-resources:
try (Connection conn = dataSource.getConnection("userId", "passwd", "url"),
PreparedStatement pStatement = conn.prepareStatement(childSql)) {
// processing steps
}
Since Connection and PreparedStatement implement the AutoCloseable interface they will be closed automatically when the try block ends. This is possible since Java 7.
I've been learning about tests lately but this is the first test were I've had to pass a variable in a function that I'm mocking. I've written a similar test were the only difference is that i use an ArgumentMatcher in this test because the testInput.validate() needs 3 Strings to pass with it. I don't know this stuff very well so I'm sorry if the terminology is off.
Here is the code i'm trying to test:
#Component
public class RequestHandler {
private static Gson gson = new Gson();
private final UserRepository userRepository;
private final TestInput testInput;
#Autowired
public RequestHandler(UserRepository userRepository, TestInput testInput) {
this.userRepository = UserRepository;
this.testInput = testInput;
}
public String addUser(String username, String email, String password) {
if (testInput.validate(username, email, password) && !(userRepository.findById(email).isPresent())) {
User user = new User(username, email, password);
userRepository.save(user);
return gson.toJson(user);
} else {
return gson.toJson("error");
}
}
}
And here is my test:
public class RequestHandlerTest {
UserRepository userRepository = Mockito.mock(UserRepository.class);
TestInput testInput = Mockito.mock(TestInput.class);
RequestHandler requestHandler = new RequestHandler(userRepository, testInput);
String test = ArgumentMatchers.anyString();
#Test
public void addUserTest() {
Mockito.when(testInput.validate(test, test, test)).thenReturn(true, false);
Mockito.when(userRepository.findById(test).isPresent()).thenReturn(false, true);
String jsonUser = new Gson().toJson(new User("username123","example#mail.com","12344321"));
String jsonError = new Gson().toJson("error");
System.out.println("addUser Test1");
assertEquals(jsonUser, requestHandler.addUser("username123","example#mail.com","12344321"));
System.out.println("addUser Test2");
assertEquals(jsonError, requestHandler.addUser("username123","example#mail.com","12344321"));
}
}
I had a bunch of errors with this code and when I changed the ArgumentMatchers.anyString() to just ArgumentMatchers.any() I had 1 error instead of like 5.
I looked into the source code of this problem, and for information to other readers, the underlying problem was that the mocked function was declared "static". This is not evident from the posted problem.
There are many issues in your test.
You cannot use like this
String test = ArgumentMatchers.anyString();
Mockito.when(testInput.validate(test, test, test)).thenReturn(true, false);
You can clearly see from the error message what Mockito is saying when you do this
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
3 matchers expected, 1 recorded:
which means you need to pass three different instances.
This line is also not correct
Mockito.when(userRepository.findById(test).isPresent()).thenReturn(false, true);
findById should return Optional, but you are returning boolean. When you use Mockito, you should mock individual steps. What I mean is in your example you need to mock userRepository.findById(test) and then isPresent on that returned mock. You cannot skip one step and go to the next.
Here is a working code
public class RequestHandlerTest {
UserRepository userRepository = Mockito.mock(UserRepository.class);
TestInput testInput = Mockito.mock(TestInput.class);
RequestHandler requestHandler = new RequestHandler(userRepository, testInput);
#Test
public void addUserTest() {
when(testInput.validate(anyString(), anyString(), anyString())).thenReturn(true, false);
User username123 = new User("username123", "example#mail.com", "12344321");
String jsonUser = new Gson().toJson(username123);
String jsonError = new Gson().toJson("error");
when(userRepository.findById(anyString())).thenReturn(Optional.empty(),Optional.of(username123));
System.out.println("addUser Test1");
assertEquals(jsonUser, requestHandler.addUser("username123","example#mail.com","12344321"));
System.out.println("addUser Test2");
assertEquals(jsonError, requestHandler.addUser("username123","example#mail.com","12344321"));
}
}
Suppose I have the following service object
public class UserService {
#Autowired
private UserDao dao;
public void addUser(String username, String password) {
if (username.length() < 8 ) {
username = username + "random" ; // add some random string
}
User user = new User(username, password);
dao.save(user);
}
}
I want to test the behaviour of the method "addUser" when username length is less 8 and when the username is more than 8 char. How do approach in unit test UserService.addUser(...), and verify it? I am aware using assert(), but the value "password" is not available outside the addUser(...) method.
I use JUnit and Mockito.
I came up a solution, after some re-visit the problem again after some months.
The idea is to observed the object user that is being passed to UserDao. We can inspect the value of the username by doing this, hence the unit test code:
#RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
#Mock
private UserDao dao;
#InjectMock
private UserService service;
#Test
public void testAddingUserWithLessThan8CharUsername () {
final String username = "some";
final String password = "user";
doAnswer(new Answer<Object>() {
#Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
Object[] args = invocationOnMock.getArguments();
User toBeSaved = (User) args[0];
Assert.assertEquals(username + "random", toBeSaved.getPassword());
return null;
}
}).when(userDao).save(Matchers.any(User.class));
service.addUser(username, password);
}
}
Guillaume actually had the closest answer, but he answered using jMock. However, he gave me the idea on how to accomplish this, so I think he deserves some credit too.
You are testing side-effects, but fortunately, everything you need is passed to the dao.save(). First, create a UserDao (either with or without Mockito), then you can use ReflectionTestUtils to set the dao in the UserService, then you can test the values which are passed to dao.save().
Something like:
private class TestUserDao extends UserDao {
private User savedUser;
public void save(User user) {
this.savedUser = user;
}
}
#Test public void testMethod() {
UserService userService = new UserService();
TestUserDao userDao = new TestUserDao();
ReflectionTestUtils.setField(userService, "dao", userDao);
userService.addUser("foo", "bar");
assertEquals("foo", userDao.savedUser.username.substring(0, 3));
assertEquals("bar", userDao.savedUser.password);
}
Or you can user Mockito to mock out the Dao if you want.
Use a mocking framework. The example below uses JMock2, but it would be similar with EasyMock, Mockito, etc.
Also, you need to extract the username generation to something like UsernameGenmerator to be able to mock it. You need another specific test for the username generator.
private final Mockery mockery = new Mockery();
private final UserDao mockDao = mockery.mock(UserDao.class);
private final UsernameGenerator mockUserNameGenerator = mockery.mock(UsernameGenerator.class);
#Test
public void addUserUsesDaoToSaveUser() {
final String username = "something";
final String generatedUsername = "siomething else";
final String password = "a password";
mockery.checking(new Expectations() {{
oneOf(mockUsernameGenerator).generateUsername(username);
will(returnValue(generatedUsername));
oneOf(mockDao).save(new User(generatedUsername, password)); // assumes your User class has a "natueral" equals/hashcode
}});
UserService userService = new UserService();
userService.addUser(username, password);
}
And for UsernameGenerator you need test on length of the returned username:
#Test
public void leavesUsernameUnchangedIfMoreThanEightChars() {
final String username = "123456789";
final UsernameGenerator usernameGenerator = new UsernameGenerator();
assertEquals(username, userGenerator.generateUsername(username));
}
#Test
public void addsCharactersToUsernameIfLessThanEightChars() {
final String username = "1234567";
final UsernameGenerator usernameGenerator = new UsernameGenerator();
assertEquals(8, userGenerator.generateUsername(username).length());
}
Of course, depending on your "random" method, you may want to test its specific behaviour too. Apart from that, the above provide sifficient coverage for your code.
It would all depend on how your DAO's save method is implemented.
If you are actually storing to a hard-coded repository, then you will probably need to query the repository itself for the values you are intereseted in.
If you have an underlying interface which is called, then you should be able to set up a callback method and retrieve the actual value which is being saved.
I have never used Mockito so I couldn't give you exact code which does this article should address that:
Using Mockito, how do I intercept a callback object on a void method?
Consider extracting user name generation logic as dependency from UserService.
interface UserNameGenerator {
Strign generate();
}
Wire UserNameGenerator same as UserDao. And change the code to:
public class UserService {
#Autowired
private UserDao dao;
#Autowired
private UserNameGenerator nameGenerator;
public void addUser(String username, String password) {
if (username.length() < 8 ) {
username = nameGenerator.generate();
}
User user = new User(username, password);
dao.save(user);
}
}
Next create the default implementation of UserNameGenerator and move name generating logic there.
Now you can easily check behavior by mocking UserNameGenerator and UserDao.
To check use case when username is length is less than 8
String username = "123";
String password = "pass";
String generatedName = "random";
// stub generator
when(nameGenerator.generate()).thenReture(generatedName);
// call the method
userService.addUser(username, password);
// verify that generator was called
verify(nameGenerator).generate();
verify(userDao).save(new User(generatedName, password));
To check use case when username is length is greater than 8
String username = "123456789";
String password = "pass";
String generatedName = "random";
// call the method
userService.addUser(username, password);
// verify that generator was never called
verify(nameGenerator, never()).generate();
verify(userDao).save(new User(username, password));
Easiest way is to extract the part where you have the user name correction logic
if (username.length() < 8 ) {
username = username + "random" ; // add some random string
}
into a method and test the return value of that method.
public string GetValidUsername(string userName){
if (username.length() < 8 ) {
return username + "random" ; // add some random string
}
return username;
}
with this you can pass different types of username and test the behavior of your code.