10008---Trail ~ Testing the DAO
来源:互联网 发布:gta5n卡掉帧如何优化 编辑:程序博客网 时间:2024/05/26 02:21
Motivation
In this step, we will develop an interface and implementation for the Stadium DAO - a class responsible for retrieving Stadium data in the persistence layer.
In line with Test Driven Development, or TDD, we write a test first and then create all classes required to make the test pass. The following diagram illustrates how the DAO relates to other elements of the trail:
Background
There are some major benefits of using Test Driven Development such as:
- developers are encouraged to think about all required use-cases and interfaces before starting to write code. This tends to produce fewer redundant methods and a clearer time-line.
- TDD helps developers to remain focused on the goal/requirements and not get lost in implementation details
- TDD encourages good test coverage
TDD means writing tests first. To do that we need our DAO interface to be place, so the test can actually compile. We start out writing an empty DAO interface and add methods to that interface later on as we write the test. We might realize that our DAO interface methods could be simplified and changed accordingly along with the test. After few iterations of fixing interface and adjusting the test, we end up with a final version of our interface.
Initialize the junit tenant
In this trail you will create an integration test, which unlike a unit test requires access both to the database and the hybris Platform environment.
This can easily be done by using the preconfigured junit tenant in which you can execute your JUnit tests isolated from other tenants. This enables you to test business functionality using real item instances.
Initialize the junit tenant as follows:
- Log in into http://localhost:9001 as admin
- Click on the tenant-link (Platform/Tenants)
- Click on "View" under TenantID junit
- Make sure, that you check cuppy and cuppytrail and then click "Initialize Tenant"
----------------------
Write the DAO interface
Create the interface cuppytrail/src/de/hybris/platform/cuppytrail/daos/StadiumDAO.java. This describes the CRUD functionality we require, in this case only Read functionality.
package de.hybris.platform.cuppytrail.daos; import de.hybris.platform.core.model.product.ProductModel;import de.hybris.platform.cuppytrail.model.StadiumModel; import java.util.List; /** * This interface belongs to the Source Code Trail documented at https://wiki.hybris.com/display/pm/Source+Code+Tutorial * An interface for the Stadium DAO. This incorporates the CRUD functionality we require for our DAO tests to pass. */public interface StadiumDAO{ /** * Return a list of stadium models that are currently persisted. If none are found an empty list is returned. * * @return all Stadiums of system */ List<StadiumModel> findStadiums(); /** * Finds all stadiums with given code. If none is found, an empty list will be returned. * * @param code * the code to search for stadiums * @return All stadiums with the given code. */ List<StadiumModel> findStadiumsByCode(String code);}
Key points to note:
- The interface consists of methods required by the test DefaultStadiumDAOIntegrationTest.java.
- The comments describe the behavior for both "success and failure" of each method
- We don't need a "save" method - the saving mechanism is done by "model service"
- findStadiumsByCode returns a list, but because we have set unique=true in items.xml, the list will have either 1 or 0 elements
Create the DAO integration test
In this step we will write a test to demonstrate the expected behavior of our DAO. The test illustrates
- how to call the findStadiums method and what it should return when it does and does not find data
- how to call the findStadiums(String code) method and what it should return when it does and does not find data
- how to persist a Stadium
This is a bare-bones unit test and we would be well advised to expand it to demonstrate and test that the method succeeds correctly when the parameters are within range, AND that the method fails correctly (and gracefully) when the parameters are out of range. For example:
- what happens when findStadiums is called, but with an argument that
- has incorrect upper/lower case combination
- is null
- is the empty string
- has a space/invalid characters
By covering such cases, the test file
- becomes itself an essential resource for developers to learn the behavior of its methods,
- will notify the developer should he/she break the existing behavior and thus reduce bugs
Create a test class cuppytrail/testsrc/de/hybris/platform/cuppytrail/daos/impl/DefaultStadiumDAOIntegrationTest.java with the following code
/** * [y] hybris Platform * * Copyright (c) 2000-2011 hybris AG * All rights reserved. * * This software is the confidential and proprietary information of hybris * ("Confidential Information"). You shall not disclose such Confidential * Information and shall use it only in accordance with the terms of the * license agreement you entered into with hybris. * * */ package de.hybris.platform.cuppytrail.daos.impl; import static org.junit.Assert.assertEquals;import static org.junit.Assert.assertTrue; import de.hybris.platform.cuppytrail.daos.StadiumDAO;import de.hybris.platform.cuppytrail.model.StadiumModel;import de.hybris.platform.servicelayer.ServicelayerTransactionalTest;import de.hybris.platform.servicelayer.model.ModelService; import java.util.List; import javax.annotation.Resource; import org.junit.Test; /** * This class belongs to the Source Code Trail documented at https://wiki.hybris.com/display/pm/Source+Code+Tutorial * * The purpose of this test is to illustrate DAO best practices and behaviour. * * The DAO logic is factored into a separate POJO. Stepping into these will illustrate how to write and execute * FlexibleSearchQueries - the basis on which DAOs operate. * * @see "https://wiki.hybris.com/display/pm/Trail+~+DAOs" */ public class DefaultStadiumDAOIntegrationTest extends ServicelayerTransactionalTest{ /** As this is an integration test, the class (object) being tested gets injected here. */ @Resource private StadiumDAO stadiumDAO; /** Platform's ModelService used for creation of test data. */ @Resource private ModelService modelService; /** Name of test stadium. */ private static final String STADIUM_NAME = "wembley"; /** Capacity of test stadium. */ private static final Integer STADIUM_CAPACITY = Integer.valueOf(12345); @Test public void stadiumDAOTest() { List<StadiumModel> stadiumsByCode = stadiumDAO.findStadiumsByCode(STADIUM_NAME); assertTrue("No Stadium should be returned", stadiumsByCode.isEmpty()); List<StadiumModel> allStadiums = stadiumDAO.findStadiums(); final int size = allStadiums.size(); final StadiumModel stadiumModel = new StadiumModel(); stadiumModel.setCode(STADIUM_NAME); stadiumModel.setCapacity(STADIUM_CAPACITY); modelService.save(stadiumModel); allStadiums = stadiumDAO.findStadiums(); assertEquals(size + 1, allStadiums.size()); assertEquals("Unexpected stadium found", stadiumModel, allStadiums.get(allStadiums.size() - 1)); stadiumsByCode = stadiumDAO.findStadiumsByCode(STADIUM_NAME); assertEquals("Did not find the Stadium we just saved", 1, stadiumsByCode.size()); assertEquals("Retrieved Stadium's name attribute incorrect", STADIUM_NAME, stadiumsByCode.get(0).getCode()); assertEquals("Retrieved Stadium's capacity attribute incorrect", STADIUM_CAPACITY, stadiumsByCode.get(0).getCapacity()); } }
Key points to note:
- We have written this test before implementing the interface. This encourages us to think about the required behavior before writing any methods helping to write only methods that are required and making sure that all essential tests are covered.
- Notice that this test class extends ServicelayerTransactionalTest (which, in turn, extends ServicelayerTest). From ServicelayerTest, our test class inherits some platform-related and persistence-related helper methods. But by extending ServiceLayerTransactionalTest (i.e., the preferred mechanism), each test method automatically begins a service-layer transaction upon invocation, then automatically performs a rollback upon completion. This provides a convenient form of isolation all of your service-layer test methods. For more details on unit-testing in the hybris suite, look here.
Run the test
- Right-click cuppytrail/testsrc/de/hybris/platform/cuppytrail/daos/impl/DefaultStadiumDAOIntegrationTest.java in Eclipse's Package Explorer and select RunAs|JunitTest
- Execution will fail (you will get unhandled Exceptions) because an implementation of StadiumDAO cannot be found. We will write this next.
Write the DAO implementation
Write the DAO functionality in the class cuppytrail/src/de/hybris/platform/cuppytrail/daos/impl/DefaultStadiumDAO.java, using hybris' Flexible Search Query for the queries, and the ModelService's save method for saving.
package de.hybris.platform.cuppytrail.daos.impl; import de.hybris.platform.cuppytrail.daos.StadiumDAO;import de.hybris.platform.cuppytrail.model.StadiumModel;import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;import de.hybris.platform.servicelayer.search.FlexibleSearchService; import java.util.List; import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component; @Component(value = "stadiumDAO")public class DefaultStadiumDAO implements StadiumDAO{ /** * We use hybris' FlexibleSearchService for running queries against the database * * @see "https://wiki.hybris.com/display/release5/FlexibleSearch" */ @Autowired private FlexibleSearchService flexibleSearchService; /** * Finds all Stadiums by performing a FlexibleSearch using the {@link FlexibleSearchService}. */ @Override public List<StadiumModel> findStadiums() { // Build a query for the flexible search. final String queryString = // "SELECT {p:" + StadiumModel.PK + "} "// + "FROM {" + StadiumModel._TYPECODE + " AS p} "; final FlexibleSearchQuery query = new FlexibleSearchQuery(queryString); // Note that we could specify paginating logic by providing a start and count variable (commented out below) // This can provide a safeguard against returning very large amounts of data, or hogging the database when there are // for example millions of items being returned. // As we know that there are only a few persisted stadiums in this use case we do not need to provide this. //query.setStart(start); //query.setCount(count); // Return the list of StadiumModels. return flexibleSearchService.<StadiumModel> search(query).getResult(); } /** * Finds all Stadiums by given code by performing a FlexibleSearch using the {@link FlexibleSearchService}. */ @Override public List<StadiumModel> findStadiumsByCode(final String code) { final String queryString = // "SELECT {p:" + StadiumModel.PK + "}" // + "FROM {" + StadiumModel._TYPECODE + " AS p} "// + "WHERE " + "{p:" + StadiumModel.CODE + "}=?code "; final FlexibleSearchQuery query = new FlexibleSearchQuery(queryString); query.addQueryParameter("code", code); return flexibleSearchService.<StadiumModel> search(query).getResult(); }}
Further Steps
Extend the integration test to test and demonstrate more use-cases.
The more use cases covered in the test, the more robust it will be and the more "living" documentation a new developer will be able to to turn to.
Add the following code to DefaultStadiumDAOIntegrationTest.java. Many more failure modes can be added.
@Testpublic void testFindStadiums_EmptyStringParam(){ //calling findStadiumsByCode() with an empty String - returns no results final List<StadiumModel> stadiums = stadiumDAO.findStadiumsByCode(""); assertTrue("No Stadium should be returned", stadiums.isEmpty());} @Test(expected = IllegalArgumentException.class)public void testfindStadiums_NullParam(){ //calling findStadiumByCode with null should throw an IllegalArgumentException stadiumDAO.findStadiumsByCode(null); //method's return value not captured}
If you have problems running the unit tests, please check the following:
Troubleshooting
- Make sure that you have activated the right extensions for the JUnit tenant
- Make sure that you have initiated the JUnit tenant
- If you have errors connecting to the Database, you might be running HSQLDB with the platform still running. Since you are only allowed a single DB connection with HSQLDB, you will need to shut down the server before running your unit test
- 10008---Trail ~ Testing the DAO
- hybris学习笔记:Trail ~ Testing the DAO
- 10009---Trail ~ Testing the Services
- hybris学习笔记:Trail ~ Testing the Services
- hybris学习笔记:Trail ~ Testing the Facades
- 10010---Trail ~ Testing the Façades
- (1.4.1) Trail ~ Integration in the hMC
- (1.5) Trail ~ Populating the Data Model
- 10006---Trail ~ Integration in the hMC
- 10007---Trail ~ Populating the Data Model
- Unit Testing DAO Classes with JUnit, Spring
- Testing, the Next Generation
- The classfy of testing
- The data for testing
- The process of testing
- Testing Out the iPhone
- The future of testing
- Testing the CATCHER
- 矩阵快速幂专题(二)
- MySQL多表查询
- u-boot网络启动分析(二) 驱动注册
- 【day0402】C++标准异常
- 【bzoj3329】【Xorequ】【数位dp+矩阵乘法】
- 10008---Trail ~ Testing the DAO
- Android Service通信
- 安卓开发中利用java代码修改控件位置
- [BZOJ3130][Sdoi2013]费用流 做题笔记
- 【HowTo ML】正则化
- FATAL EXCEPTION: main 2. java.lang.NoSuchFieldError: R$id.r1
- C语言如何实现一个函数返回另一个函数
- 6 Java基础语法(二维数组,参数传递与数据加密问题)&面向对象(面向对象思想,类与对象及使用,对象内存图解)
- Android ExpandableListView 进行二级扩展 (BaseExpandableListAdapter)