Step 1: Lets say we have a AccountService class that we want to subject under test. While testing, we want to supply mocks for BankAccountService and CashTransactionService. But use the real CalcEngine.
package com.myapp.services;
import static com.jpmorgan.wss.aes.calculation.strongersuper.engine.CalcEngineDroolsHelper.isNull;
//..
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Resource;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component("accountService")
public class AccountService
{
@Resource(name = "cashTransactionService")
private CashTransactionService cashTransactionService;
@Resource(name = "bankAccountService")
private BankAccountService bankAccountService;
@Resource(name = "calcEngine")
private CalcEngine calcEngine;
@Transactional(readOnly = true)
public List<balances> calcTransaction(int accountId)
throws IOException
{
//..............uses cashTransactionService, bankAccountService, and calcEngine
}
//...other methods
}
Step 2: The jBehave step class with Spring DI.
package com.myapp.bdd.steps;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.drools.runtime.StatelessKnowledgeSession;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;
import org.jbehave.core.model.ExamplesTable;
import org.joda.time.DateTime;
import org.mockito.Mockito;
import org.springframework.stereotype.Component;
@Component
public class CashTransactionRulesStep
{
@Resource(name = "accountService")
private AccountService accountService;
@Resource(name = "cashTransactionService")
private CashTransactionService cashTransactionService;
@Resource(name = "bankAccountService")
private BankAccountService bankAccountService;
BankAccount bankAccount = new BankAccount();
List<CashTransaction> cashTransactionsList = Collections.EMPTY_LIST;
List<Transaction> result = null;
@Given("a bankAccountCd = $bankAccountCd and bankAccountNm = $bankAccountNm")
public void bankAccountDetails(String bankAccountCd, String bankAccountNm)
{
bankAccount.setAccountCd(bankAccountCd);
bankAccount.setAccountNm1(bankAccountNm);
}
@When("calcTransaction method is fired with portfoliocd = $portfolioCode")
public void calcTransaction(String portfolioCode)
{
try
{
Mockito.when(
cashTransactionService.findByAccountDt(Mockito.anyInt(), (Date) Mockito.anyObject(),
(Date) Mockito.anyObject())).thenReturn(cashTransactionsList);
Mockito.when(
bankAccountService.getBankAccount(Mockito.anyInt())).thenReturn(bankAccount);
result = transactionService.calcTransaction(1);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
//......
}
Step 3: Now the Spring config class that overrides DI in AccountService with fully and partially mocked injection. The resource names need to be same to override, and nor defined under @ComponentScan but defined with @Bean.
package com.myapp.bdd.stories;
import org.mockito.Mockito;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Import;
@Configuration("AccountingStoryConfig")
@ComponentScan(
basePackages =
{
"com.myapp.bdd",
"com.myapp.accounting",
},
useDefaultFilters = false,
includeFilters =
{
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ValidatorChain.class),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = TransactionValidator.class)
})
@Import(
{
StoryConfig.class //import other cobfigs
})
public class AccountingStoryConfig
{
@Bean(name = "accountService")
public TransactionService getAccountService()
{
return Mockito.spy(new AccountServiceImpl()); //partially mock
}
@Bean(name = "cashTransactionService")
public CashTransactionService getCashTransactionService()
{
return Mockito.mock(CashTransactionServiceImpl.class); //fully mock
}
@Bean(name = "bankAccountService")
public BankAccountService getBankAccountService()
{
return Mockito.mock(BankAccountService.class); //fully mock
}
}
Step 4: Finally, for completion sake, the jBehave story class that can run as jUnit test.
package com.myapp.bdd.stories;
import java.util.List;
import org.jbehave.core.io.CodeLocations;
import org.jbehave.core.io.StoryFinder;
import org.springframework.batch.core.configuration.support.ClassPathXmlApplicationContextFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AccountStory extends AllStories
{
public AccountStory()
{
super();
}
protected ApplicationContext context()
{
if (context == null)
{
try
{
ClassPathXmlApplicationContextFactory factory = new ClassPathXmlApplicationContextFactory(null);
factory.setApplicationContext(new AnnotationConfigApplicationContext(AccountStoryConfig.class));
context = factory.createApplicationContext();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
return context;
}
@Override
protected List<string> storyPaths()
{
return new StoryFinder().findPaths(
CodeLocations.codeLocationFromClass(getClass()), "**/account.story", "");
}
}
0 comments:
Post a Comment