WillMcavoy
WillMcavoy

Reputation: 1815

Test a void method with conditioned loop using mockito

I have following method which asks for user input until valid user credentials are entered.It then generates id for that user and sets registered =TRUE.

1.How can I check the value of local variable "registered" from my unit test?

2.How can I assert in my test that while loop executed until "registered" became TRUE?

private void register() {

    boolean registered=false;
    while(!registered){
        try {
            String uname =this.read("User Name : ");
            char password[] = this.readPassword();
            String serverURL = this.read("Server URL : ");

            if(!uname.isEmpty() && password!=null && !serverURL.isEmpty()){ 

                registered=this.getUID(uname,password,serverURL);
            }
            if(registered==false)
                System.out.println("\nPlease verify your details and try again!\n");

        } catch (UnsupportedEncodingException e) {} 
        catch(Exception e){}    
    }
    System.out.println("Successful");
}

I have come across usage of ArgumentCaptor to capture variables that a method to be tested, uses to invoke another methods.

e.g verify(mockObj).intArgumentMethod(argument.capture());

However I am not passing variable "registered" to any other method otherwise i would have captured it.

Upvotes: 0

Views: 1235

Answers (2)

bric3
bric3

Reputation: 42283

Don't test the implementation details, test the behavior given certain input. If the registered variable is supposed to be some sort of output then it shouldn't be a local variable.

One design I like is to use method objects, it is possible to pass arguments at object creation, and an object method can have multiple return values.

class Registrator {
    Registrator(...) { /* assigning needed field */ }

    void register() { /* logic that will mutate internal fields */ }

    boolean registered() { return registered; }
    long triesCount() { return triesCount; }
    // ...
}

And one can adapt the code to use a Report object, on which the register method can append success / failure / more details like reasons / etc.

And the test would be much more easy to write.

Upvotes: 0

CoronA
CoronA

Reputation: 8095

  1. You cannot
  2. By verification:
    • The loop invariant is that registered is false. So the loop is not entered if it is true
    • The loop is exited
      • at the bodies start (in this case it is true)
      • if a Throwable is thrown, that is not caught by 'catch(Exception e)' (in this case it might be anything)

Anyway - review your testing strategy:

  • a function has input parameters and output parameters
  • the input should be part of the fixture:

    this.read("User Name : ")
    this.readPassword()
    this.read("Server URL : ")
    this.getUID(uname,password,serverURL) // this may also be viewed as output
    
  • the output should be part of the assertions

    System.out.println(...)
    

The input can be set up by creating anonymous sub classes, e.g.

fixture = new YourClass {
  public String read(String prompt) {
    return mockedString;
  }
  ...
};

The output can be captured/asserted by a Junit Rule, e.g. StandardErrorStreamLog

Mockito is not needed with this example method.

Upvotes: 1

Related Questions