1 00:00:00,890 --> 00:00:02,140 For testing the weather service, 2 00:00:02,140 --> 00:00:05,980 we're going to need to dive a bit deeper into the Spring Test Framework. 3 00:00:05,980 --> 00:00:08,578 Currently, our application's WeatherServiceImpl, 4 00:00:08,578 --> 00:00:10,370 let me open that WeatherServiceImpl. 5 00:00:11,900 --> 00:00:14,460 Currently, this class depends on properties that are loaded 6 00:00:14,460 --> 00:00:18,920 from a properties file, you see that with the PropertySource annotation. 7 00:00:18,920 --> 00:00:22,843 As well as an Autowired bean in the Impl's superclass, 8 00:00:22,843 --> 00:00:25,930 which you see here is the RestApiService and 9 00:00:25,930 --> 00:00:31,020 the Autowired bean that it depends on is this RestTemplate bean. 10 00:00:31,020 --> 00:00:35,280 Now, you recall from earlier in the workshop, I mentioned that RestTemplate is 11 00:00:35,280 --> 00:00:40,240 a way that we can use the Spring Framework to call upon external APIs. 12 00:00:41,570 --> 00:00:46,080 The problem with these Autowired fields, as well as anything that receives its 13 00:00:46,080 --> 00:00:50,620 value from a value annotation that comes from a properties file, 14 00:00:50,620 --> 00:00:54,820 is that since we aren't loading the entire application context right now, 15 00:00:54,820 --> 00:00:59,190 these things will not be injected in our tests. 16 00:01:00,370 --> 00:01:03,670 No worries though, the Spring Test Framework offers us an option. 17 00:01:03,670 --> 00:01:09,210 We can load a test context by providing a test specific configuration class. 18 00:01:09,210 --> 00:01:12,340 Let's add our weather service test and get started. 19 00:01:12,340 --> 00:01:17,030 So I'm back in the test source folder and 20 00:01:17,030 --> 00:01:20,085 I'm going to add a class for weather service test. 21 00:01:21,650 --> 00:01:25,878 WeatherServiceTest. 22 00:01:25,878 --> 00:01:29,941 For starters, we'll need to use Spring's JUnit runner so 23 00:01:29,941 --> 00:01:33,761 we'll annotate the class with a RunWith annotation and 24 00:01:33,761 --> 00:01:39,710 specify the SpringJunit4ClassRunner as the JUnit runner to be used for these tests. 25 00:01:41,140 --> 00:01:44,100 And next, in order to trigger the loading of a test context, 26 00:01:44,100 --> 00:01:49,777 we'll annotate this class with a ContextConfiguration annotation. 27 00:01:51,260 --> 00:01:54,810 Now without specifying a class or to location as an annotation element 28 00:01:54,810 --> 00:01:58,160 on this ContextConfiguration annotation, Spring will look for 29 00:01:58,160 --> 00:02:03,050 classes annotated with the configuration annotation in the current class. 30 00:02:03,050 --> 00:02:07,750 So let's add a static class within WeatherServiceTest. 31 00:02:07,750 --> 00:02:11,122 So I will say Configuration and 32 00:02:11,122 --> 00:02:15,668 call it public static class TestConfig. 33 00:02:18,291 --> 00:02:21,627 Now to get those properties from api.properties, 34 00:02:21,627 --> 00:02:26,404 I'll annotate this class with the same type of PropertySource annotation 35 00:02:26,404 --> 00:02:29,385 that we saw in our WeatherServiceImpl class. 36 00:02:29,385 --> 00:02:34,466 So PropertySource, and I'll say api.properties here, 37 00:02:34,466 --> 00:02:40,060 and then I will add as a field an Autowired environment variable. 38 00:02:40,060 --> 00:02:46,060 So, Autowired Environment, I'll call it env. 39 00:02:47,840 --> 00:02:49,840 And remember that Autowired RestTemplate? 40 00:02:49,840 --> 00:02:52,840 Let's make that available as a bean here. 41 00:02:52,840 --> 00:02:57,686 So we'll call it Bean public RestTemplate, 42 00:02:57,686 --> 00:03:00,880 there it is, restTemplate. 43 00:03:02,650 --> 00:03:04,350 There we go. 44 00:03:04,350 --> 00:03:07,510 Now we don't have to duplicate code from our AppConfig 45 00:03:07,510 --> 00:03:09,210 where the production bean is located. 46 00:03:09,210 --> 00:03:10,910 Let's head there to reconfigure some things. 47 00:03:10,910 --> 00:03:14,184 So I'll open AppConfig.java. 48 00:03:14,184 --> 00:03:16,940 And here is that RestTemplate bean right here. 49 00:03:18,450 --> 00:03:21,600 You'll find that as you gain experience writing tests, 50 00:03:21,600 --> 00:03:24,900 you'll get better at writing code that's more testable and test friendly. 51 00:03:24,900 --> 00:03:30,760 So it's the code in this RestTemplate bean here that we'd rather not duplicate. 52 00:03:30,760 --> 00:03:34,230 What we can do is make a static method that loads a default RestTemplate and 53 00:03:34,230 --> 00:03:35,990 this production bean can utilize it. 54 00:03:35,990 --> 00:03:38,760 Also, our test can then utilize it as well. 55 00:03:38,760 --> 00:03:40,982 So, I will make that right here. 56 00:03:40,982 --> 00:03:48,594 We'll say public static RestTemplate, and again, call it restTemplate. 57 00:03:48,594 --> 00:03:53,250 Actually, I'll call this one defaultRestTemplate. 58 00:03:53,250 --> 00:03:56,340 There we go, now I'll move all the code from here 59 00:03:56,340 --> 00:04:01,500 down into the static method just like this. 60 00:04:01,500 --> 00:04:05,795 With one exception, this static method doesn't need that 61 00:04:05,795 --> 00:04:10,490 RequestFactory here since all that really does, if you look at this, 62 00:04:10,490 --> 00:04:14,380 is it sets some connection and read timeout. 63 00:04:14,380 --> 00:04:16,330 We won't need that for our tests for now. 64 00:04:17,430 --> 00:04:20,800 Also, this would cause a problem for us since the method, 65 00:04:20,800 --> 00:04:26,190 this ClientHttpRequestFactory method, that is an instance method and 66 00:04:26,190 --> 00:04:30,940 this one is a static method so we could not call upon this method from here. 67 00:04:33,050 --> 00:04:35,760 Now we can go back up here to the production bean and 68 00:04:35,760 --> 00:04:37,700 tweak it a little bit so that it's still intact. 69 00:04:37,700 --> 00:04:41,110 So I'll create a RestTemplate here, I'll just call it rt, and 70 00:04:41,110 --> 00:04:44,550 call that default static method here. 71 00:04:44,550 --> 00:04:49,690 And then, I'll just set the RequestFactory here calling upon 72 00:04:49,690 --> 00:04:52,630 that method below, and this is an instance method so 73 00:04:52,630 --> 00:04:55,890 it can indeed call this instance method down here. 74 00:04:55,890 --> 00:04:58,049 Okay, everything's intact and 75 00:04:58,049 --> 00:05:03,068 we now have this public static method where we can call it from the test class. 76 00:05:03,068 --> 00:05:07,094 And I do see that I'm missing my return value here, so 77 00:05:07,094 --> 00:05:12,230 I'll return that RestTemplate so that it is available as the bean. 78 00:05:12,230 --> 00:05:15,250 So now that we have things set up in a more reusable manner in our application 79 00:05:15,250 --> 00:05:17,150 code, let's switch back to the test. 80 00:05:17,150 --> 00:05:18,920 I'm gonna close this file. 81 00:05:18,920 --> 00:05:25,690 Okay, so in our test, we can now call upon that static method from AppConfig. 82 00:05:25,690 --> 00:05:30,631 So I'll just return AppConfig.defaultRestTemplate, 83 00:05:30,631 --> 00:05:31,846 good enough. 84 00:05:31,846 --> 00:05:36,242 And another bean that we'll need to make available is a WeatherService bean, 85 00:05:36,242 --> 00:05:40,238 we'll have to do this because it is our application class that contains 86 00:05:40,238 --> 00:05:42,121 the ComponentScan annotation. 87 00:05:42,121 --> 00:05:46,886 If I go to Application.java, I see the ComponentScan annotation which will tell 88 00:05:46,886 --> 00:05:51,926 Spring that when it boots the application, remember, the application not the test, 89 00:05:51,926 --> 00:05:56,136 when Spring boots the application, it'll scan the current package and 90 00:05:56,136 --> 00:05:59,610 any sub packages of whatever application is located here. 91 00:06:00,610 --> 00:06:02,910 So it'll scan all these sub packages for 92 00:06:02,910 --> 00:06:07,780 any Spring components that are annotated with service, repository, or 93 00:06:07,780 --> 00:06:12,440 any other Spring components that may be present in these packages. 94 00:06:13,680 --> 00:06:16,326 Now this includes the service, 95 00:06:16,326 --> 00:06:21,031 the WeatherServiceImpl that we are going to be testing. 96 00:06:21,031 --> 00:06:25,746 This is annotated with a service, so when the application boots, 97 00:06:25,746 --> 00:06:30,546 this WeatherService will be picked up as an auto-wireable bean and 98 00:06:30,546 --> 00:06:34,040 we need that to be the case in our test as well. 99 00:06:34,040 --> 00:06:37,570 So we'll need to construct and return the implementation ourselves. 100 00:06:37,570 --> 00:06:40,939 Let's go back into our test and add that as a bean. 101 00:06:40,939 --> 00:06:42,404 So we'll say Bean. 102 00:06:44,714 --> 00:06:51,447 Public WeatherService weatherService. 103 00:06:51,447 --> 00:06:53,730 And in here let's construct this. 104 00:06:53,730 --> 00:07:00,390 So WeatherService, I'll just call it service = new, 105 00:07:00,390 --> 00:07:04,400 I'll have to create the implementation myself and 106 00:07:04,400 --> 00:07:10,910 pass in all those values that we can now grab from the env field. 107 00:07:10,910 --> 00:07:13,790 Okay, so let me do that on separate lines here. 108 00:07:13,790 --> 00:07:20,009 So I'll say env.getProperty, and the first one is weather.api.name. 109 00:07:20,009 --> 00:07:23,502 And I'll just copy that and paste it a few times. 110 00:07:23,502 --> 00:07:32,249 The next one we'll say is weather.api.key and 111 00:07:32,249 --> 00:07:39,110 the next one is weather.api.host. 112 00:07:39,110 --> 00:07:41,240 Cool, I've created my service implementation, 113 00:07:41,240 --> 00:07:46,200 and now let's return it as the bean. 114 00:07:46,200 --> 00:07:48,550 Cool, and at this point we're ready to write our test for 115 00:07:48,550 --> 00:07:52,490 the weather service which is exactly what we're going to do in the next video.