Setting Up DBUnit for DAO Tests10:56 with Chris Ramacciotti
When testing the data (DAO) layer of our application, it's helpful to have some assistance in starting our tests with some test data, and even verifying our resulting database after a test executes. Our assistance comes from a library called DBUnit, and in this video I show you how to configure your tests to use it.
Sync Your Code to the Start of this Video
git checkout -f v9
Using Git with this Workshop
See the README on Github for information on how to use Git with this repo to follow along with this workshop.
As the final step toward our database, we finally arrived at the Dao layer. 0:00 This particular project leverages Spring Data JPA, 0:04 which is definitely a handy tool that can accelerate our productivity. 0:07 Let me open favoritedao to remind you what that looks like. 0:11 Spring Data JPA repositories allow us to write interfaces that extend 0:15 others such as this CrudRepository interface. 0:19 And when we fire up our app, Spring Data will generate the implementations 0:22 of these repositories or what we're calling Dao's. 0:25 In this project, I have no explicitly defined implementation class for 0:29 this interface. 0:33 Again, that is provided by Spring Data when we boot this app. 0:35 Now there are a bunch of methods provided by this CrudRepository interface that we 0:39 might want to use in our application code. 0:43 If we open that class, we can see a bunch of them listed here. 0:46 We can save an entity or a collection of entities. 0:49 We can find one given its identifier, 0:54 we can check if one exists given its identifier, and 0:57 we can simply grab all of the entities and there are more methods as well. 1:01 Now just as it's important for 1:08 us to write unit tests that sufficiently cover our business logic, 1:09 it's also important that we don't spend needless time testing dependencies of our 1:13 code base that have already been extensively tested by its developers. 1:16 And what I mean is that we don't need to test the CrudRepository's find one or 1:20 save methods. 1:24 We choose our dependencies based on our trust of their reliability and 1:26 robustness, which in part comes from comprehensive testing. 1:29 But what we will do here is see how to test the parts of this layer that we did 1:33 customize. 1:36 If I go back here I can see everything that I customized, 1:38 like this findAll method, which includes a custom query. 1:41 Or this brand new method that I wrote that is called saveForCurrentUser. 1:44 So as a last step here in the workshop, we'll focus on testing the favorite Dao. 1:50 Let's go ahead and create a package and test for that. 1:55 So in com.teamtreehouse, I need to create a new package called the dao, 1:59 and then let's create a new class called FavoriteDaoTest. 2:05 These tests will involve a bit more set up for a couple reasons. 2:12 First, our Dao methods have custom queries that inject authenticated user data. 2:15 If I go back to FavoriteDao, you'll see all these references, 2:20 in fact all of these methods here that I've customized, 2:23 include a reference to this principal thing right here. 2:26 This is the security principal coming from Spring Security. 2:30 Essentially, it's the authenticated users ID that's getting injected as a query, 2:36 you can see that these sort of resemble SQL queries. 2:41 Just to give you an idea of what this looks like when I call this Dao's findAll 2:46 method, what's happening here is I'd like this method to not return 2:51 all entities that are saved in the favorite table in the database. 2:55 What I'd like to do is select all favorites 2:58 whose user is the currently authenticated user. 3:02 And in that table I've stored the user's ID, so 3:06 I say where f.user.id= the authenticated user's id, so I get 3:09 only the favorites in the findall method that match the currently logged in user. 3:15 So in order to make this authentication data available to us in our tests, 3:21 we'll need that user detailed service as a bean, 3:26 as well as our user entity map by hibernate. 3:29 And hey, speaking of hibernate, we'll also need the favorite entity mapped. 3:31 And finally since we're using Spring Data, 3:35 we'll need those implementations generated as well. 3:37 It is for all these reasons that we are actually going to technically make 3:41 this an integration test, by having the test create an application context. 3:45 By doing this, 3:49 we'll have our entire application's beans available if we wanted them. 3:50 When using Spring Data, this is often a reasonable approach, since generating 3:55 implementations for those repositories would be unreasonably time consuming. 3:59 And, part of these tests is making sure that those implementations are indeed 4:04 generated correctly. 4:09 So how do we make this an integration test? 4:12 Well, easy, we add spring boots spring application configuration annotation to 4:15 the class SpringApplicationConfiguration just like that. 4:20 And we tell it which class contains the top level annotations, 4:25 you could also specify a list of configuration classes here. 4:30 Now to make sure this annotation is processed, 4:36 we better use spring's junit runner. 4:38 So I'll use RunWith(SpringJUnit4ClassRunner). 4:41 The next thing we'll have to tackle is how to start with a preexisting set of data, 4:48 now there are various tools out there but 4:54 the one that we'll use to help us is called DV unit. 4:56 We'll use it to inject a set of starter data into our database so that we have 4:59 some users, roles and favorites ready to go when we want to test. 5:02 And to set this up in the test we'll apply DB unit's database setup annotation. 5:06 So I'll apply that right here, @DatabaseSetup annotation. 5:12 And in here I'll reference where the file is located that is going to contain 5:17 our test data, and that is the favorites.XML file on the classpath. 5:23 This tells DB unit to inject the reference data into our 5:30 in memory test database which is an H2 database before starting our test. 5:32 Note that you can apply the DatabaseSetup annotation to individual methods too, 5:38 but by applying the annotation to the class, 5:43 the reference data is injected before each test method. 5:45 Kinda like a setup method annotated with the before annotation. 5:49 Okay, one more annotation to apply to the class, and 5:52 that's the test execution listeners' annotation. 5:55 So let's add that one in there, TestExecutionListeners() and 5:58 in here, I will provide a couple test execution listeners, 6:04 DependencyInjectionTestExecutionListener, as well as DbUnitTestExecutionListener. 6:09 Back those up tab wise, cool. 6:17 Now according to the Spring docs a test execution listener in Spring, 6:21 defines a listener API for acting to test execution of events. 6:25 We need this DependencyInjectionTestExecutionListener 6:31 so that our autowired dependencies can be injected from the loaded application 6:35 context. 6:39 In our case, we're going to need to inject the Dao under test, 6:40 which is the favorite Dao, so let's autowire that. 6:44 Autowired, private_FavoriteDao, I'll just call it dao. 6:50 Now, as for the DbUnitTestExecutionListener, 6:57 we needed to allow DB unit to inject data into our test database. 7:01 Okay, the final set up we're going to do for this Dao test, before actually writing 7:05 our test in the next video, is to create that starter data set as an XML file. 7:09 The test class path route is the resources directory in the test source directory. 7:14 So let's create our XML file there. 7:21 So under the test source directory, I'm going to create a new 7:24 file called resources/favorites.xml and 7:29 that will create that resources directory if it doesn't already exist. 7:37 Cool, there we go. 7:42 These data files are called Flat XML data files, 7:44 where we can create one file with entries into as many tables as we like. 7:47 We put all the data into a root node of dataset, just like that. 7:51 Now for each row of data we'd like to insert into our test database we create 7:56 an XML element inside this dataset element, 8:00 whose tag name is the name of the entity that we are inserting, 8:03 which will be the same as the name of the database table. 8:07 I'll demonstrate this first with a role. 8:10 So I'll create a role element here, and 8:12 to specify the column values we use XML attributes. 8:17 So I'll say this ID is 1, and the name of this should be ROLE_ USER. 8:22 So I'm inserting a row into the role table with an ID column of 1 and 8:27 a name column of ROLE_USER. 8:34 Let's do this for a couple users as well. 8:37 So I'll give myself a couple of blank lines there. 8:42 And I'll say user, and in here I'll say the id=1, 8:44 and the username is, I'll just say user1. 8:50 The password is password, we won't go too complicated here. 8:56 I'll say the account is enabled. 9:01 And the role ID since that is the join column, the role ID is going to be 1. 9:05 So that's the ID that comes from the role table. 9:13 And I only have one here so I only have one to work with. 9:16 Now let's copy that and paste it as a second user. 9:19 I'll just change a couple pieces of information here, roll1 as well. 9:24 Okay, so I have user1 and user2. 9:28 Finally lets add a few rows into the favorites table two for user one and 9:33 one for user two again give myself a blank line. 9:36 Favorite, and I'll say its id is 1 and 9:41 the user it belongs to is user 1. 9:46 Let's create a couple more and this id is 2, this id is 3. 9:49 This is the favorite id itself, so these should all be unique. 9:56 And these are the users that these favorites belong to, so 10:00 I'll give user one two favorites and user two one favorite. 10:05 Now feel free to go crazy with this data on your own. 10:10 Keep in mind though that for this kind of testing, I'm choosing to include only as 10:12 much data as is needed to verify the functionality I am testing, for example 10:16 I've chosen three favorites here so that when we test the Dao's find all method, 10:21 I can verify that there are indeed two favorites associated with user 1. 10:27 And that we don't incorrectly get one favorite that is the one favorite for 10:30 user two, or three favorites for all favorites. 10:35 If I chose two favorites for 10:38 each, I wouldn't be able to tell by sheer number whether or not the proper 10:40 favorites were returned by the Dao's since each user would have two favorites. 10:44 All right, with all our set up out of the way, 10:50 let's take a quick break before wrapping up our work with Dao tests. 10:52
You need to sign up for Treehouse in order to download course files.Sign up