您的位置:首页 > 大数据 > 人工智能

10008---Trail ~ Testing the DAO

2016-04-02 19:55 525 查看


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


how to start?

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"

Another way of initializing the junit tenant is to run the antyunitinittarget.

----------------------


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.
@Test
public 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: