JUnit to retrieve value from database to test criteria - junit5

How do I write JUnit with actual service/repository call to retrieve data from a database table instead of using a mock service/repository?
Here the below code returns an empty list of object, whereas I am expecting few hundred objects. findAll() is a simple method for which I am trying to write JUnit but later on I will be writing JUnit for a method which takes Map as JSON from request parameters and forms a criteria API so in this case, I would like to test
Request
Parsing of the request in Controller(what controller receives)
And forming the SQL Criteria and returned object and that's the reason I don't want to mock service/repository.
I am using Spring Boot Rest Controller and for Unit Testing, I am using Mocikito and JUnit.
#ActiveProfiles("test")
#RunWith(SpringRunner.class)
#WebMvcTest(CaDetailController.class)
public class CaDetailControllerTest {
private static ObjectMapper objectMapper = null;
private List<CaDetail> caDetails;
#Autowired
private MockMvc controller;
#MockBean
CaDetailRepository repository;
#BeforeClass
public static void beforeClass() {
objectMapper = new ObjectMapper();
}
#Before
public void before() {
caDetails = new ArrayList<CaDetail>();
}
#After
public void after() {
caDetails = new ArrayList<CaDetail>();
}
#AfterClass
public static void afterClass() {
objectMapper = null;
}
#Test
public void getCorporateActions() throws Exception {
MvcResult result = controller.perform(MockMvcRequestBuilders.get("/api/ca").accept(MediaType.APPLICATION_JSON)).andReturn();
caDetails = objectMapper.readValue(result.getResponse().getContentAsByteArray(), new TypeReference<List<CaDetail>>() {
});
System.out.println(">>>>>>>>>>>>>>> caDetails : " + caDetails);
assertNotNull(caDetails);
assertTrue(caDetails.size() > 0);
}

You need to write integration test for your services which will directly communicate with database. For example go through this link.
http://www.springboottutorial.com/integration-testing-for-spring-boot-rest-services

Related

Cannot read properties when used MockWebServer

Hi I am new to the Junit Testing and am trying to test the third party call, for that I have used MockWebServer from okhttp3, the mockWebServer does the job of giving me a proper mocked response but in the class that I am trying to test has the following
#Autowired
Environment env
....
...
..
String url = env.getProperty(shop.url);
The above is significant as it gets the url from application.yml
But the env is null whenever I am running that particular test method which uses MockWebServer
Main Class
Class ConnectionService {
#Autowired
Environment environment;
public ConnectionService(WebClient.Builder builder) {
this.webClient = builder.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.baseUrl(usersBaseUrl).build();
}
public void getShops(){
...
..
String url = env.getProperty(shop.url);
..
..
}
Test Class
#ExtendWith(SpringExtension.class)
#SpringBootTest
#AutoConfigureWireMock(port = 0)
class ConnectionServiceTest {
public static MockWebServer mockWebServer;
private static ConnectionService connectionService;
#BeforeAll
public static void setUp() throws IOException {
mockWebServer = new MockWebServer();
connectionService = new ConnectionService(WebClient.builder(),
mockWebServer.url("/").toString();
}
#AfterAll
static void tearDown() throws IOException {
mockWebServer.shutdown();
}
#Test
void testMethod() {
MockResponse mockResponse = new MockResponse()
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody("{\"status\":\"up\",\"details\":\"details\"}")
.throttleBody(16, 5, TimeUnit.SECONDS);
mockWebServer.enqueue(mockResponse);
connectionService.getShops();
}
}
Could someone please help me out figure what am I doing wrong, is it the MockWebServer that is causing environment to be null ? even the other properties in other files are null. Thanks in advance :)
I tried to test the WebClient by making use of MockWebServer, although it worked but now I cannot read any properties either from application.yml or otherProperties.properties as the environments variables are not getting injected

Why WebApplicationFactory is saving state from previous builds?

I will try to show my problem with a sample code easier to understand.
I have used WebApplicationFactory to develop my acceptance tests. Let's say that I have the typical minimal Program.cs with the following line to register one of my modules:
builder.Services.RegisterModule<StartupRegistrationModule>(builder.Configuration, builder.Environment);
And this module is declared like this:
internal sealed class StartupRegistrationModule : IServiceRegistrationModule
{
public static Dictionary<string, string> _dictionary = new();
public void Register(IServiceCollection services, IConfiguration configuration, IHostEnvironment hostEnvironment)
{
// Lot of modules being registered
_dictionary.Add("key", "value");
}
}
One of my tests file is like this:
public sealed class MyTests : AcceptanceTestBase
{
[Fact]
public void Test1()
{
// arrange
// act
// assert
}
[Fact]
public void Test2()
{
// arrange
// act
// assert
}
[Fact]
public void Test3()
{
// arrange
// act
// assert
}
}
And AcceptanceTestBase is:
public abstract class AcceptanceTestBase : IDisposable
{
protected HttpClient _httpClient;
protected WebApplicationFactory<Program> _webApplicationFactory;
public AcceptanceTestBase()
{
_webApplicationFactory = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
// ... Configure test services
});
_httpClient = _webApplicationFactory.CreateClient();
}
public void Dispose()
{
_httpClient.Dispose();
_webApplicationFactory.Dispose();
}
}
If I try to execute all these tests my tests will fail in the second test run because the WebApplicationFactory is trying to build again the Application but it already has the key in the dictionary and it will fail. See the image for more understanding on the problem.
So my question is, how can I build the application in different scopes to do not share this dictionary state?
Thanks :)
Update:
The real static dictionary is saved behind this nuget package that keeps the track of all my circuit breaker policies state. I do not actually need even the HttpClients for my tests but did not find a way to remove them and not load this. I tried removing all the HttpClients to see if it also removes their dependencies, but it does not seem to make the trick.
It is because you are using:
internal sealed class StartupRegistrationModule : IServiceRegistrationModule
{
/// .. static here
public static Dictionary<string, string> _dictionary = new();
public void Register(IServiceCollection services, IConfiguration configuration, IHostEnvironment hostEnvironment)
{
// Lot of modules being registered
_dictionary.Add("key", "value");
}
}
The static Dictionary is shared over all your tests because they run in the same process.
Each test starts a new (Test-)WebHost but the dictionary remains untouched.
My proposal is to not use statics anywhere in DI context to prevent such hidden traps.
I don't know the purpose of your Dictionary here but maybe you can extract this to a singleton registration which you can replace in your (Test.)WebHost on each new test / startup?

How to write Xunit test case of factory design pattern code block which is tightly coupled?

I would like to write xunit test case of below method. Could you please suggest alternate design so i can write xunit test case with minimum change in my current project.
public ActionResult Index(int id = 0, AssetFilterType filter = AssetFilterType.All)
{
using (var tracer = new Tracer("AssetController", "Index"))
{
RemoveReturnUrl();
ViewBag.JobId = id;
var response = ContextFactory.Current.GetDomain<EmployeeDomain>().GetEmployeeFilterAsync(id,
CurrentUser.CompanyId, filter); // Not able write unit test case , please suggest alternate design.
return View("View", response);
}
}
current design is as follow
public interface IDomain
{
}
public interface IContext
{
D GetDomain<D>() where D : IDomain;
string ConnectionString { get; }
}
public class ApplicationContext : IContext
{
public D GetDomain<D>() where D : IDomain
{
return (D)Activator.CreateInstance(typeof(D));
}
public string ConnectionString
{
get
{
return "DatabaseConnection";
}
}
}
public class ContextFactory
{
private static IContext _context;
public static IContext Current
{
get
{
return _context;
}
}
public static void Register(IContext context)
{
_context = context;
}
}
//var response = ContextFactory.Current.GetDomain**< EmployeeDomain>**().GetEmployeeFilterAsync(id,
CompanyId, filter);
This line serve purpose to call specific class method i.e GetEmployeeFilterAsync from EmployeeDomain. Although it is very handy and widely used in our application but due to design issue i am not able to write unit
test case.
Could you please suggest design so with the minimum change we can write unit test case.
Don't use the Service Locator anti-pattern, use Constructor Injection instead. I can't tell what AssetDomain is from the OP, but it seems as though it's the dependency that matters. Inject it into the class:
public class ProbablySomeController
{
public ProbablySomeController(AssetDomain assetDomain)
{
AssetDomain = assetDomain;
}
public AssetDomain AssetDomain { get; }
public ActionResult Index(int id = 0, AssetFilterType filter = AssetFilterType.All)
{
using (var tracer = new Tracer("AssetController", "Index"))
{
RemoveReturnUrl();
ViewBag.JobId = id;
var response = AssetDomain.GetAssetFilterAsync(id, CurrentUser.CompanyId, filter);
return View("View", response);
}
}
}
Assuming that AssetDomain is a polymorphic type, you can now write a test and inject a Test Double:
[Fact]
public void MyTest()
{
var testDouble = new AssetDomainTestDouble();
var sut = new ProbablySomeController(testDouble);
var actual = sut.Index(42, AssetFilterType.All);
// Put assertions here
}
step1 : Required library
step 2 : When the application starts , register required domain like
protected void Application_Start()
UnityConfig.RegisterComponents();
Step 3: create one static class and register all your domain
example
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
Initialize domain which will injected in controller
container.RegisterType<IPricingDomain, PricingDomain>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
step 4 :
so you can inject respective interface in constructor
in controller file.
goal : get rid of below any pattern in your project.
and start writing unit test cases.

how to pass parameters to a test case while running it using Junit Suite

I want to run multitple Junit tests i have created in a package. Every test needs region and server paramter to load the correct data files. I am using System.getProperty to fetch region and serverdetails for all junit tests. I am not sure how to pass these parameters in a TestSuite Runner. Here is the test case i have created
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ExpenseTests {
private static String server = System.getProperty("server");
private static String region = System.getProperty("region");
#BeforeClass
public static void setup() throws Exception {
SetUp setUp = new SetUp(region, server);
Login(region, server);
CreateClient(region, server);
}
#Test
public void test1_checkexpense() {
// code here
}
#Test
public void test2_addbasicExpense() {
//code here
}
#AfterClass
public static void teardown() throws Exception {
quit(webpage);
}
}
Here is the TestSuite
#RunWith(Suite.class)
#Suite.SuiteClasses({
ExpenseTests.class
AnotherTest.class
})
public class SmokeTestSuite {
}
I can run ExpenseTest using mvn install -Dtest="ExpenseTests" -Dserver="prod" -Dregion="us" but how do i pass region and server details in above SmokeTestSuite?
I think you may use Global variable to pass parameter to all test cases.
Example
public static String server = System.getProperty("server");
public static String region = System.getProperty("region");
Then pass it to all test cases.

Spring Data neo4j JUnit4 setup

I confess I am a total newbie at the Java way of doing things and I am totally lost trying to get a simple unit test running.
I am building a data access library and want to unit test it. I am using Spring Data Neo4j 4.0.0.BUILD-SNAPSHOT because I need to connect to a remote Neo4j server in the real world.
After battling errors all day I am at the point where I have a test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ComponentScan(basePackages = {"org.mystuff.data"})
#ContextConfiguration(classes={Neo4jTestConfiguration.class})
public class PersonRepositoryTest {
#Autowired
PersonRepository personRepository;
protected GraphDatabaseService graphDb;
#Before
public void setUp() throws Exception {
graphDb = new TestGraphDatabaseFactory().newImpermanentDatabase();
}
#After
public void tearDown() {
graphDb.shutdown();
}
#Test
public void testCreatePerson() throws Exception {
assertNotNull(personRepository);
Person p = new Person("Test", "User");
personRepository.save(p);
}
}
Neo4jTestConfiguration.java
#Configuration
#EnableNeo4jRepositories(basePackages = "org.mystuff.data")
#EnableTransactionManagement
public class Neo4jTestConfiguration extends Neo4jConfiguration {
#Bean
public SessionFactory getSessionFactory() {
return new SessionFactory("org.mystuff.data");
}
#Bean
public Neo4jServer neo4jServer() {
// What to return here? I want in-memory database
return null;
}
#Bean
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
return super.getSession();
}
}
When running tests the personRepository.save() throws and exception 'No Scope registered for scope "session"'
I don't know if I need the configuration class but my test class won't work without it because Spring needs #ContextConfiguration and I want all the DI niceness Spring provides (amongst other things).
How can I get my tests to work with Spring?
You can use an InProcessServer which is an in-memory database:
#Bean
public Neo4jServer neo4jServer() {
return new InProcessServer();
}
Omit the session scope as your test isn't running in a web container. An example: https://github.com/neo4j-examples/sdn4-cineasts/blob/4.0-RC1/src/test/java/org/neo4j/cineasts/PersistenceContext.java
This will require dependencies as described in this question: Spring Data Neo4j 4.0.0.M1 Test Configuration
In your test class PersonRepositoryTest, you don't need to construct an instance of the database, your tests will run against the same InProcessServer.
Here's an example: https://github.com/neo4j-examples/sdn4-cineasts/blob/4.0-RC1/src/test/java/org/neo4j/cineasts/domain/DomainTest.java