0

So I'm new in java and in testing and I keep trying to test this function but i could not find a way. Any test goes. The function is part of bigger class called SignUp, that has other methods aswell. I know its not very well done :)

public static String newDayOfBirth() {
        Scanner scanner = new Scanner(System.in);
        String dayOfBirth = scanner.nextLine();
        if(Integer.parseInt(dayOfBirth) > 0 && Integer.parseInt(dayOfBirth) < 32){
            return dayOfBirth;
        }
        else {
            System.out.println("Eneter a valid day of birth");
            dayOfBirth = scanner.nextLine();
            return dayOfBirth;
        }
    }
DJoke
  • 3
  • 1
  • 5
    What do you mean by test it? Unit test it as part of a suite? Invoke it so you can test it manually? – robinsax May 12 '20 at 19:25

3 Answers3

2

The problem is that there is a scanner involved. You really need to split out the handling of input from System.in to somewhere else and change this method to take that text as input and parse and validate that input.

Restrict methods to one piece of behaviour in order to unit test them and isolate behaviour that can't be unit tested (eg handling manual input from system.in) and cover that in integration tests.

Chris
  • 1,644
  • 1
  • 11
  • 15
  • 1
    You can also mock `System.in` as in [this post] [https://stackoverflow.com/questions/31635698/junit-testing-for-user-input-using-scanner] – roninjoe May 12 '20 at 19:49
  • 1
    I know, but i really don't have the knowledge to do that (to mock System.in). I mean i can copy from somewhere probably, but I would not understand and for me it does not make sense right now. I want to take it step by step – DJoke May 12 '20 at 20:33
  • That's very sensible - in that case, I'd take out the validation logic into a method called something like isValidDay that takes in a String and returns a Boolean - very trivial method but easy to unit test. Then the method that takes input calls that method and prompts user to try again if necessary. For now be pragmatic, don't test that method. Later on, you might have a chance to look into the details of mocking System.in and you can add a test then. For now, don't worry. – Chris May 12 '20 at 20:58
  • Mocking `System.in` is a bad idea anyway. Parameterize the code with input and output stream, or a `Console` (which could be mocked). – erickson May 12 '20 at 20:58
0

You'd want to invoke it in the test and then check validity of response ( what is a valid date of birth? Any valid date? One with age more than X?)

akapulko2020
  • 1,079
  • 2
  • 22
  • 36
  • Well i know testing his has really no purpose, other than entering 2 invalid bdays consecutively, I'm just trying to get used to testing and I was trying to test anything in this method in any way possible without changing it. And to answer your question, yes I'm trying to test the validity of a date of birth. (for example, what i get if i put 0, -10, 45, a random string etc.) – DJoke May 12 '20 at 20:30
  • So you'd need to run the method, get results, compare to expected result , or check result validity, or verify an exception got thrown when it should have been - using Junit assert compare methods and then a test will pass if all ok and fail otherwise – akapulko2020 May 13 '20 at 05:15
0

You can mock Scanner using PowerMocktio using

@PrepareForTest({
TargetClass.class,
Scanner.class
})
@RunWith(PowerMockRunner.class)
public class Test {

   private TargetClass target;

   @Before
   public void setUp() {
      target = new TargetClass();
   }

   @Test
    public void shouldDoSomething() {
      // Arrange
      whenNew(Scanner.class).withAnyArgument().thenReturn(mockedScanner);
      when(scanner.nextLine()).thenReturn("line");

      // Act
      String actual = target.newDayOfBirth();

      // Assert
      assertEquals("line", actual);
    }
}
0xh3xa
  • 4,801
  • 2
  • 14
  • 28