[ Team LiB ] |
6.7 Breaking Up Methods to Avoid Mock Objects6.7.1 ProblemYou want to test a method without resorting to the complexity of mock objects. 6.7.2 SolutionSplit the method into smaller pieces, ensuring that each piece performs one task. Small, single-purpose methods improve code quality in addition to making them testable. 6.7.3 DiscussionExample 6-12 shows a method that is hard to test. It is hard because you must create a mock ResultSet implementation in order to write your tests. Example 6-12. Hard to test// fetch an account type code from the database and convert it // into one of the Account constants int getAccountType(ResultSet rs, String acctTypeColName) throws SQLException, DataSourceException { String acctStr = rs.getString(acctTypeColName); if ("SA".equals(acctStr)) { return Account.SAVINGS; } if ("CH".equals(acctStr)) { return Account.CHECKING; } throw new DataSourceException("Unknown account type: " + acctStr); } The fundamental problem is that this method performs two tasks, rather than one. It is also a little messy because it throws two types of exceptions. The first task is to retrieve data from the ResultSet. The second task is to convert that data into some other form. When confronted with a method like this, do not try to write a sophisticated unit test. Instead, first try to simplify the method. Example 6-13 shows a simplified version of this method. It is now assumed that the caller obtains the account code from the database before calling this method, whose sole purpose is converting that string into a Java constant. Example 6-13. The same logic, now testable// convert a database account code, such as "CH", into a Java constant int getAccountType(String acctTypeStr) throws DataSourceException { if ("SA".equals(acctTypeStr)) { return Account.SAVINGS; } if ("CH".equals(acctTypeStr)) { return Account.CHECKING; } throw new DataSourceException("Unknown account type: " + acctTypeStr); } You can now test this method without resorting to mock objects. We also eliminated the extra SQLException because we no longer use JDBC in this method. Example 6-14 shows the test. Example 6-14. Test for the getAccountType( ) methodpublic void testGetAccountType( ) throws Exception { AccountFactory acctFact = new AccountFactory( ); assertEquals("account type", Account.CHECKING, acctFact.getAccountType("CH")); assertEquals("account type", Account.SAVINGS, acctFact.getAccountType("SA")); try { acctFact.getAccountType("bogus"); fail("Expected DataSourceException"); } catch (DataSourceException expected) { } } 6.7.4 See AlsoThis method was taken from Example 6-8 earlier in this chapter. |
[ Team LiB ] |