0

I have a class which is used for email validation. The class has two private String fields out of which i have injected the value of one from application.properties.

public class EmailValidation {

    private final String someString = "xyz"

    @Value("${regex}")
    private String emailRegex;

    // methods
}


public class EmailValidaitonTest {

   private final EmailValidation obj = new EmailValidation();

   //missing emailRegex
}

Now i have to write a unit test for this. This class has no dependency, so i just decided to use the new operator in EmailValidationTest class for the class object. Now, i can access the String someString but i cannot have the value of emailRegex since it was injected by Spring. How can i set its value in the test class and i want its value to be same as in my application.properties.

Navjot Singh
  • 678
  • 7
  • 18
  • 2
    Use constructor injection instead of field injection. Then you can pass whatever regex you want in your unit tests. If you want to create an integration test and let Spring inject the property, then don't use `new`, and instead autowire the bean in your test. The documentation is your friend. – JB Nizet Nov 17 '18 at 15:10
  • I used constructor injection for that regex field but now how to initialize it with `new` inside the test class since it now requires a string to be passed. Should i hardcode the string to be passed? @JBNizet – Navjot Singh Nov 17 '18 at 15:15
  • As I said, if you want Spring to inject the value, then your test whould be a Spring test: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing. But what's the point of externalizing the regex in the first place? – JB Nizet Nov 17 '18 at 15:19
  • it is a very long regexp so i decided to put it in application.properties file. Is it not a good practice? @JBNizet – Navjot Singh Nov 17 '18 at 15:26
  • 2
    This value will never change, right? It doesn't depend on the environment, the profile, or anything, right? So there's no reason to externalize it. If there is a good reason to externalize it, that means it could have any value, decided by whoever decides to change the value, and your test should thus not care what specific value is in the properties: it should work with any value. – JB Nizet Nov 17 '18 at 15:28
  • 1
    Also, note that the standard hava bean validation, supported by Spring Boot, has an email validator already, so you're reinventing the wheel. – JB Nizet Nov 17 '18 at 15:29

2 Answers2

1

It's preferable if you can write unit tests without loading up Spring context. You can have your class set up like this:

public class EmailValidation {

    private final String regex;

    @Autowired
    EmailValidation (@Value("${regex:}") String regex) {
        this.regex = regex;
    }
}

Now in your test class, you can instantiate your emailValidation class through constructor param.

private final EmailValidation obj = new EmailValidation("myRegex");

As @JB Nizet points out, it's better to have a static final field for valid email regex or just call through a library.

夢のの夢
  • 5,054
  • 7
  • 33
  • 63
1

You use ReflectionTestUtils.setField to inject property value in test cases.

 public class EmailValidationTest{
     private @InjectsMock EmailValidation validation; 
     private String emailRegexPattern = "^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$";

     @BeforeAll
     public void setUp(){
        ReflectionTestUtils.setField(validation, "emailRegex", emailRegexPattern);
     }

    //your test cases over here.
    }
Gaurav Srivastav
  • 2,381
  • 1
  • 15
  • 18