junit nested mock injections for characterization tests
I need to be able to mock nested classes that have been injected using JUnit so I can create characterization tests. The problem is:
class 1 is using an object of class 2 and class 2 is using an object of class 3. And class 3 object is null when test is run on a class 1 method
this is the class structure I have:
class 1 {
@Inject private Class2 class2 ;
}
class 2 {
@Inject private Class3 class3 ;
}
my test suite needs to run from the top down in order to fully test my system as it is an old system and I need to write tests starting from the top in order to gradually refactor it.
Test suite:
@RunWith(MockitoJUnitRunner.class)
public class Class1Test {
@Mock
Class3 class3;//this doesn't work object remains null inside of mocked class2
@Mock
Class2 class2; //this injection works and the object isn't null inside of class1
@InjectMocks
public Class1 class1;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testFunction()
{
assertNotNull(class1.exampleFunction());
}
}
I know the correct way is to stub dependencies, but this codebase is far too large to have to write unit tests for every layer, I need to be able to write tests in JUnit so that way I can run these tests while refactoring the codebase to make sure I haven't broken anything, hence why I haven't used postman since I need it to be quick.
on java 8 @inject is a java annotation using JUnit 4 but I think I can use junit5 if I need to. the project is a j2ee (java ee ) application
1 answer
-
answered 2021-03-03 05:39
Praveen Kumar
If I understood the problem correctly, class 1 is using an object of class 2 and class 2 is using an object of class 1. And class 3 object is null when test is run on a class 1 method.
You can use deep stubbing for class 2.
@Mock(answers=Answers.RETURNS_DEEP_STUBS) Class class2;
See also questions close to this topic
-
recursion method not returning a string
I have to create a code that can find the longest palindrome contained inside sentences. (eg. Some people like cake but I prefer pie; the longest palindrome is i prefer pi). The problem is that upon running the code it doesn't return the palindrome. I'm not sure what the problem is but if anyone can figure it out I'd appreciate you letting me know. Thanks!
Code is below...
public class Recursion6 { static String recursion(String word, int currentLength, int x, String substring) { String reverse =new StringBuffer(word).reverse().toString(); if(word.length() == 1 ){ return substring; } if(word.charAt(0) != word.charAt(x)) { if(x == word.length() - 1) { recursion(word.substring(1), currentLength, 1, substring); } x++; recursion(word, currentLength, x, substring); } else { if(word.substring(0, x + 1).equalsIgnoreCase(reverse.substring(word.length() - (x+1), word.length()))) { if(word.substring(0, x).length() > currentLength) { currentLength = word.substring(0, x + 1).length(); substring = word.substring(0, x + 1); } recursion(word.substring(1), currentLength, 1, substring); } recursion(word.substring(1), currentLength, 1, substring); } return substring; } public static void main(String[] args){ Scanner sc=new Scanner(System.in); System.out.println("Enter a Sentence:"); String word=sc.nextLine(); System.out.println("The Palendrome is "+recursion(word.replaceAll(" ", ""), 1, 1, null)); sc.close(); } }
-
Groovy v3.0.7 doesn't support static interface methods
I have created a simple example groovy script under groovy v3.0.7, and Java 11.0.5
interface IFace { static String sMethod () { return "hello" } } class Test implements IFace { } IFace i = new Test() println i.sMethod()
however the parrot parser won't except this. If you run this you gives the following error
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed: ideaGroovyConsole.groovy: 2: The method 'java.lang.String sMethod()' from interface 'IFace' must not be static. Only fields may be static in an interface. @ line 2, column 5. static String sMethod () { ^ 1 error
Why doesn't the latest 3.0.7 build support static interface methods. Have I missed something ?
-
HTTP Post method not supported by this URL when deployed to jboss EAP 7.1
I've a REST API, that is deployed on JBoss EAP 7.1. When I hit the URL at
http://localhost:8080/MyApp/group
in postman, it gives "HTTP method POST is not supported by this URL" error with status code 405.
When I deploy this API on embedded tomcat server, it works perfectly fine. Here is my controller
@RestController public class RequestController { @Autowired private GroupService groupService; @PostMapping( "/group" ) public GroupInfo fetchGroupInfo( @RequestBody GroupInfo groupInfo ) { long groupId = groupInfo.getGroupId(); return groupService.getGroup( groupId ); } }
main class
@SpringBootApplication public class MyApp extends SpringBootServletInitializer { /** * @param args */ public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder){ return builder.sources(MyApp.class); } }
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.my.package</groupId> <artifactId>MyApp</artifactId> <version>0.0.1-SNAPSHOT</version> <name>MyApp</name> <packaging>war</packaging> <properties> <java.version>1.8</java.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.4.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> </dependencies> <build> <finalName>MyApp</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
The deployment shows no error messages. However, it does show below warning
WARN [org.jboss.weld.deployer] (MSC service thread 1-4) WFLYWELD0013: Deployment optumRx-0.0.1-SNAPSHOT.war contains CDI annotations but no bean archive was found (no beans.xml or class with bean defining annotations was present).
And the class files are missing in the deployment folder in jboss. Can you please tell, what am I missing?
-
What would be a proper "man or boy test" to check if a given language has good support for functional programming idioms?
The original Man or boy test was devised by Donald Knuth to to distinguish compilers that correctly implemented "recursion and non-local references" from those that did not. I'm not asking about this original version.
My issue is, sometimes people argue if not-pure-functional language A or B has better support for functional programming idioms. It's common, for example to read complaints about Python lacking good support for those who like to write code in functional style, due to lambdas limited to one line, or lack of tail call optimization, that blows recursive functions after a depth around 1000. I think this is not a exaustive list.
This context bears my question: In the spirit of the original Man or boy test, what would be a simple routine involving the main functional programming idioms, like deep recursion, lambdas, et cetera, that we coud try to implement in any language to separate the man-functional from the boy-functional?
-
Accessing Page Date On Failure
I have a need to access page data if a test fails in cypress, but I am unable to perform any cy.get() operations. The code operates in the following way:
- A test executes.
- At some point, it attempts to get an element using cy.get(). If the element does not exist, other elements will appear that contain error message data. The error message data elements may or may not exist.
- If the element being sought does not exist, Cypress.on('fail', (error, runnable) => ...) is invoked. It is in this code block I would like to access the error message data.
Is there any way to use Cypress to access the html elements in the on fail handler? Or is there a different approach I should be taking?
-
react-native regex to match with digit + one character
I need to test if my string match with a certain format, this one : "20/04/1980"
So I tried to write a regex but I test only digits with it :.match(/\d{2}\.\/\d{2}.\/\d{4}/)
How can I test the match with also the "/" character ?
-
UnsupportedClassVersionError jakarta ee9 dummy project on glassfish using java 8
I am trying to run a dummy jakarta ee9 project on glassfish6 using jdk 8 using intellij version (2020.3.3) . But it is complaining that I am trying to run java 11 compiled files using a java 8. Please see the reported error.
com/sun/enterprise/admin/remote/RemoteSuccessException has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
But I checked couple of times my glassfish version and jdk version to see whether I made a silly version mistake here and there but I could not figure out the error.
Could one someone share some pointer
corretto-1.8.0_282\jre\bin\java.exe -Dfile.encoding=windows-1252 -classpath "C:\Program Files\JetBrains\IntelliJ IDEA 2020.3.3\lib\idea_rt.jar" com.intellij.rt.execution.CommandLineWrapper C:\Users\chand\AppData\Local\Temp\idea_classpath1547555230 com.intellij.javaee.oss.process.JavaeeProcess 51191 com.intellij.javaee.oss.glassfish.agent.Glassfish51Agent Error running admin process: Message: com/sun/enterprise/admin/remote/RemoteSuccessException has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0 Stack trace: java.lang.UnsupportedClassVersionError: com/sun/enterprise/admin/remote/RemoteSuccessException has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0 at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
-
How to fix java.lang.ClassNotFoundException in servlet?
**I'm trying to use functions of the class IUserImplDAO which implements from an Interface **the error in the console
The Class works well outside of the servlet but inside this later doesn't . I'm working with hibernate in my project
-
Yet another JSTL absolute URI cannot be resolved Issue
Tried different approaches after going through similar questions on StackOverflow but none of them worked. Following is my pom.xml file
<properties> <maven.compiler.target>14</maven.compiler.target> <maven.compiler.source>14</maven.compiler.source> <junit.version>5.7.1</junit.version> </properties> <dependencies> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.5</version> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>javax.persistence-api</artifactId> <version>2.2</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>3.3.1</version> </plugin> </plugins> </build>
URI in my JSP:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
In my JSP file, Intellij is giving me which URI to use, not showing any errors. But getting a 500 error upon calling the JSP page. -
Why is WebTestClient not returning the JSON object from this GET test
I'm just starting to learn to work with Spring. I created a little REST endpoint and am trying to setup a junit test. I'm following a book, which is very similar to the example shown here: https://rieckpil.de/spring-webtestclient-for-efficient-testing-of-your-rest-api/
The API works on its own, but when I run the test no body is received -- I think. Am I missing something here?? All I get is this:
... Tomcat started on port(s): 65376 (http) with context path '' ... > GET http://localhost:65376/order/A1 > WebTestClient-Request-Id: [1] > Accept: [application/json] No content < 200 OK OK < Date: [Wed, 21 Apr 2021 14:46:57 GMT] < content-length: [0]
Here is my test class
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment=RANDOM_PORT) class WebsiteBackendPocApplicationTests { private static final String ORDER_ID_OK = "A1"; @Autowired private WebTestClient client; @MockBean private OrderServiceImpl orderService; @Before public void setUp() { when(orderService.getOrder(ORDER_ID_OK)).thenReturn(new Order(ORDER_ID_OK,"T",null)); } @Test public void contextLoads() { } @Test public void getOrderById() { client.get().uri("/order/" + ORDER_ID_OK) .accept(APPLICATION_JSON) .exchange() .expectStatus() .isOk() .expectHeader() .contentType(APPLICATION_JSON) .expectBody() .jsonPath("$.orderId").isEqualTo("A1"); } }
Here is my implementation of the API
@RestController public class OrderServiceImpl implements OrderService { private final ServiceUtil serviceUtil; @Autowired public OrderServiceImpl(ServiceUtil serviceUtil) { this.serviceUtil = serviceUtil; } @Override public Order getOrder(String orderId) { List<Item> itemList = new ArrayList<Item>(); itemList.add(new Item("123",3.50,3)); itemList.add(new Item("124",9.20,2)); if (orderId.equals("A2")) { throw new NotFoundException("This order does not exist: " + orderId); } return new Order("A1","A", itemList); } }
And the API definition.
public interface OrderService { @GetMapping( value = "/order/{orderId}", produces = "application/json") Order getOrder(@PathVariable String orderId); }
-
Different behavior Real vs Test
Assume we had a basic Thread implementation
public void run() { while(true) { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } //atomic int System.out.println("running..."+i.getAndIncrement()); } } }
and in Main(both Real and @Test_JUnit )
MyThread t = new MyThread("thread_1"); t.start();
Question is why on Real the behavior is fine (running indefinite) and in Test is stopping after few steps(and no exceptions) ?
Note: There are no additional setting for test environment (and maybe another question: Can test setting be changed in order to get the same behavior as Real)
-
Capture arguments of a static method call in Mockito
I am trying to unit test a method call in android studio using Mockito. It is something like this:
public static class DeviceMessageHandler extends Handler { public DeviceMessageHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { try { switch (msg.what) { default: String message = (String) msg.obj; DeviceRequest deviceRequest = new Gson().fromJson(message, DeviceRequest.class); String requestType = deviceRequest.getKey(); if (DeviceMessage.SOME_ACTION.equals(requestType)) { sendResponseWithMessage(execId, COMMAND_STATE, "Not accepted"); } } } } } public static void sendResponseWithMessage(String execId, String commandState, String reasonIfAny) { // do some work } catch (Exception e) { e.printStackTrace(); } }
So here I am able to call sendResponsewithMessage. I want to check the parameters being passed when I am calling this method. The problem being that it is a static method and I do not know how to capture parameters passed to a static method. I tried using PowerMock but since this is an android project, I am not able to use PowerMock. Any way I can assert the parameters passed on the method call with expected values?
-
EF Core 5 - Update an entity with SQL does not work
I have an application that use EF Core 5 with SQL Server for production/dev and SQLLite for integration tests.
In SQL server all works perfectly but with SQLLite in my test my entity is not updated.
Let's go with some code and explanation.
Model Buidler
Here my model builder configuration for my entity :
modelBuilder.Entity<Order>(order => { order.ToTable("Orders"); order.HasKey(s => s.Id); order.Property(i => i.ConcurrencyStamp).IsRowVersion(); order.Property(i => i.ShippingExcludingTaxes).HasColumnType("decimal(10,2)"); order.Property(i => i.ShippingIncludingTaxes).HasColumnType("decimal(10,2)"); order.HasMany(s => s.OrderItems).WithOne() .Metadata.PrincipalToDependent.SetPropertyAccessMode(PropertyAccessMode.Field); order.Metadata.FindNavigation(nameof(Order.OrderItems)).SetPropertyAccessMode(PropertyAccessMode.Field); order.HasOne<Payment>(p => p.Payment) .WithOne() .HasForeignKey<Order>(p => p.PaymentId); order.HasOne<Address>(s => s.ShippingAddress) .WithOne() .HasForeignKey<Order>(p => p.ShippingAddressId); order.OwnsOne(lc => lc.Contact); });
I already read that RowVersion does not work like in SQLServer, here I use a string generated by a Guid and here the code to update it in each savechanges ( classic & async ):
private void UpdateLastUpdate() { var entries = ChangeTracker .Entries() .Where(e => e.Entity is Entity && ( e.State == EntityState.Added || e.State == EntityState.Modified)); foreach (var entityEntry in entries) { ((Entity)entityEntry.Entity).LastUpdate = DateTime.Now; ((Entity)entityEntry.Entity).ConcurrencyStamp = Guid.NewGuid().ToString(); } }
Domain class & Tested method
Here is my entity that I want to update
public class Order : Entity, IAggregateRoot { public string UserId { get; set; } public decimal ShippingIncludingTaxes { get; set; } public decimal ShippingExcludingTaxes { get; set; } public OrderState State { get; set; } public string PaymentId { get; set; } public Payment Payment{ get; set; } private readonly List<OrderItem> _orderItems = new List<OrderItem>(); public IReadOnlyCollection<OrderItem> OrderItems => _orderItems; public string ShippingAddressId { get; set; } public Address ShippingAddress { get; set; } public OrderContact Contact { get; set; } public ICollection<OrderHistory> OrderHistories { get; set; } public decimal TotalIncludingTaxes => _orderItems.Sum(s => s.TotalIncludingTaxes) + ShippingIncludingTaxes; //some other stuff }
and the attributes that I am updating In my test
//method is in Order.cs public void SetInProgress(OrderHistory history) { State = OrderState.InProgress; OrderHistories = OrderHistories ?? new List<OrderHistory>(); OrderHistories.Add(history); }
Test and assert
So I run my integration test, all works and I see that my DBContext take my changes. But when It comes to make the assert, the entity is the same before the test
public class OrderControllerTest : IClassFixture<IntegrationTestFixture> { private readonly IntegrationTestFixture _fixture; public OrderControllerTest(IntegrationTestFixture fixture) { _fixture = fixture; Init().GetAwaiter().GetResult(); } private IRepository<OrderHistory, UserContext> _orderHistoryRepository; private IRepository<Nursery, PlantContext> _nurseryRepository; private IRepository<Order, UserContext> _orderRepository; private Nursery nursery; private async Task Init() { _orderHistoryRepository = _fixture.Services.GetService<IRepository<OrderHistory, UserContext>>(); _nurseryRepository = _fixture.Services.GetService<IRepository<Nursery, PlantContext>>(); _orderRepository = _fixture.Services.GetService<IRepository<Order, UserContext>>(); nursery = await _nurseryRepository.FindAsync(a => a.LegalNumber == NurseryService.LEPAGE_LEGALNUMBER); } [Fact] [Trait("Category", "Integration")] public async Task OrderController_SendOrders_ShouldBeOkWithOrders() { await _orderRepository.AddAsync(OrderGenerator.GenerateOrder(OrderState.Validated, nursery.Id)); var result = await _fixture.GetAsync("api/order/send"); result.IsSuccessStatusCode.Should().BeTrue(); var histories = await _orderHistoryRepository.FilterAsync(s => true); var orders = await _orderRepository.FilterAsync(s => true); histories.Should().NotBeEmpty(); orders.All(all => all.State == OrderState.InProgress).Should().BeTrue(); } }
Here when I test if my orders have InProgress state, the result is false because the State is Validated ( the state does not change since the creation ).
If somebody have an idea ? If the error occurred because of the Guid row version, if any configuration exist to make my test working ?
-
How to reset database after test?
I am using
PHPUnit
as a tool in my tests, so my question is what should I do to reset my database and remove the data I inserted during the testing? -
Spring security and integration test
I need help to integrate Spring Security features with a suite of Integration Test built with SpringBootTest and RestAssured/Hamcrest. The test suite was working fine before adding the Spring Security features.
Below the security configuration:
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests(authorizeRequests -> authorizeRequests .anyRequest().authenticated() ).oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt); } }
An example of integration test:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class CategoryIntegrationTest { @LocalServerPort private int port; private String createURLWithPort(String uri) { return "http://localhost:" + this.port + "/categories" + uri; } @Test void shouldGet() { // prepare ... given().contentType("application/json") .when().get(this.createURLWithPort("/" + entitySaved.getCategoryId())) .then() .statusCode(HttpStatus.SC_OK) .body("name", equalTo(entitySaved.getName())); } }
All test return 401 error. How can I authenticate spring during the test? I'm using spring cloud, with a authentication in gateway and KeyCloak as authentication provider.