การทดสอบ SpringBoot Controller โดยใช้ Mockito & jUnit5 ล้มเหลวเนื่องจาก Spring ไม่สามารถสร้าง bean ของคลาส PropertyService ซึ่งโหลดคุณสมบัติได้

ฉันมีโปรเจ็กต์การบูตสปริงแบบง่าย ๆ

นี่คือโครงสร้างโครงการ -

ป้อนคำอธิบายรูปภาพที่นี่

ถ้าฉันรันแอพพลิเคชั่น Spring Boot มันจะทำงานได้ดีโดยไม่มีข้อผิดพลาดใดๆ ฉันสามารถรับลูกค้าทั้งหมด รับลูกค้ารายเดียว ลบลูกค้า และเพิ่มลูกค้าด้วยวิธีการควบคุมส่วนที่เหลือของฉัน

ผ่าน Postman ฉันสามารถเพิ่มลูกค้า--

<Customer>
<firstName>TestData</firstName>
<lastName>Test</lastName>
<gender>M</gender>
<date>2020-01-26T09:00:00.000+0000</date>
<authId>6AE-BH3-24F-67FG-76G-345G-AGF6H</authId>
<addressdto>
<city>Test City</city>
<country>Test Country</country>
</addressdto>
</Customer>

การตอบสนอง

Customer with 34 sucessfully added

ซึ่งหมายความว่าในขณะที่แอปพลิเคชันทำงานอยู่ ก็สามารถสร้างอินสแตนซ์ PropertyService.java ได้ ดังนั้นฉันจึงสามารถเข้าถึงรหัสการตรวจสอบสิทธิ์ซึ่งมีอยู่ใน application-dev.properties ถึง PropertyService.java ของฉันได้ คุณสมบัติเดียวกันนี้มีอยู่ใน src/test/resources-> application.properties ของฉัน

มีสองปัญหาคือ--

  1. ตอนนี้เมื่อฉันรันคลาส HomeControllerTest.java asjUnit test ฉันได้รับข้อผิดพลาด ฉันแก้ไขจุดบกพร่องและพบสาเหตุของข้อผิดพลาดแล้ว ภายในคลาส HomeController.java ของฉัน ไม่สามารถสร้างอินสแตนซ์ของคลาส PropertyService.java ได้ ดังนั้นฉันจึงได้รับ null pointer exception ที่นั่น ดังนั้นการดำเนินการคลาสทดสอบเพิ่มเติมจึงล้มเหลว
  2. ฉันไม่สามารถเข้าถึง authId ผ่าน PropertyService.java ในคลาสทดสอบของฉันได้ ดังนั้นฉันจึงต้องฮาร์ดโค้ด

ใครช่วยบอกฉันได้ไหมว่าทำไมฉันถึงได้รับปัญหานี้ และฉันจะแก้ไขได้อย่างไร?

HomeController.java

@PostMapping("/customer")
    public ResponseEntity<String> addCustomer(@RequestBody CustomerDto customerDto) {
        String message = "";
        ResponseEntity<String> finalMessage = null;
        try {
            if ((!customerDto.getAuthId().equals(propertyService.getKeytoAddCustomer()))) {
                System.out.println("If check failed: "+propertyService.getKeytoAddCustomer());
                System.out.println("Unauthorized access attempted");
                message = "Unauthorized access attempted";
                finalMessage = new ResponseEntity<>(message, HttpStatus.UNAUTHORIZED);
            }
            System.out.println("If check passed :"+propertyService.getKeytoAddCustomer());

            Customer customer = mapper.mapToEntity(customerDto);
            customerService.addCustomer(customer);
            message = "Customer with " + customer.getId() + " sucessfully added";
            finalMessage = new ResponseEntity<>(message, HttpStatus.OK);

        } catch (Exception e) {
            message = "Failed to add customer due to " + e.getMessage();
            finalMessage = new ResponseEntity<>(message, HttpStatus.INTERNAL_SERVER_ERROR);
        }
        return finalMessage;
    }

PS- equals(propertyService.getKeytoAddCustomer())) (ปัญหา 1) --> ที่นี่ฉันได้รับ null pointer exception

PropertyService.java

package com.spring.liquibase.demo.utility;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;

@Configuration
@PropertySource("classpath:config.properties")
public class PropertyService {
    @Autowired
    private Environment env;

    public String getKeytoAddCustomer() {
        return env.getProperty("auth.key.to.add.customer");
    }
}

HomeControllerTest.java


@ExtendWith(SpringExtension.class)
class HomeControllerTest {
    private MockMvc mvc;

    @InjectMocks
    private HomeController homeController;

    @MockBean
    private CustomerService customerService;
//
//  @Autowired
//  private PropertyService propertyService;

    @BeforeEach
    public void setup() {
        mvc = MockMvcBuilders.standaloneSetup(homeController).build();
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testaddCustomer() throws Exception {
        String uri = "/customer";
        CustomerDto custDto = this.mockCustomerObject();
        String actualResult = mvc
                .perform(MockMvcRequestBuilders.post(uri).contentType(MediaType.APPLICATION_JSON)
                        .content(asJsonString(custDto)))
                .andExpect(MockMvcResultMatchers.status().isOk()).andReturn().getResponse().getContentAsString();
        Assertions.assertEquals(actualResult, "Customer with " + custDto.getId() + " sucessfully added");
    }

    private CustomerDto mockCustomerObject() {
        CustomerDto cusDto = new CustomerDto();
        AddressDto addressDto = new AddressDto();
        addressDto.setCity("BBSR");
        addressDto.setCountry("INDIA");
        cusDto.setDate(new Date());
        cusDto.setFirstName("Biprojeet");
        cusDto.setLastName("KAR");
        cusDto.setGender("M");
        cusDto.setAuthId(" 6AE-BH3-24F-67FG-76G-345G-AGF6H");
        cusDto.setAddressdto(addressDto);
        return cusDto;

    }

    public static String asJsonString(CustomerDto cusDto) {
        try {
            return new ObjectMapper().writeValueAsString(cusDto);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

ป.ล.- ฉันได้ใส่ความคิดเห็นเกี่ยวกับรหัสแล้วเนื่องจากฉันไม่สามารถเข้าถึงไฟล์ prop ที่นี่ได้ ต้องการความช่วยเหลือที่นี่เช่นกัน (ปัญหาที่ 2)

application.properties-- ภายใน src/test/resources

# DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url=jdbc:mysql******useSSL=false
spring.datasource.username=****
spring.datasource.password=****

# Hibernate
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
logging.level.org.springframework.web=INFO
logging.level.com=DEBUG

customer.auth.key = 6AE-BH3-24F-67FG-76G-345G-AGF6H

แอปพลิเคชัน dev.properties

same as above

application.properties inside->src/main/resources

spring.profiles.active=dev
logging.level.org.springframework.web=INFO
logging.level.com=DEBUG
server.port=8080

บันทึกข้อผิดพลาด jUnit

java.lang.AssertionError: Status expected:<200> but was:<500>
    at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:59)
    at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:122)
    at org.springframework.test.web.servlet.result.StatusResultMatchers.lambda$matcher$9(StatusResultMatchers.java:627)
    at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:196)
    at com.spring.liquibase.demo.controller.HomeControllerTest.testaddCustomer(HomeControllerTest.java:50)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.base/java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:436)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170)
    at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:112)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(Unknown Source)
    at java.base/java.util.Iterator.forEachRemaining(Unknown Source)
    at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Unknown Source)
    at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
    at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
    at java.base/java.util.stream.ReferencePipeline.forEach(Unknown Source)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source)
    at java.base/java.util.stream.ReferencePipeline$2$1.accept(Unknown Source)
    at java.base/java.util.Iterator.forEachRemaining(Unknown Source)
    at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Unknown Source)
    at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
    at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
    at java.base/java.util.stream.ReferencePipeline.forEach(Unknown Source)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
    at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)


person Arpan Banerjee    schedule 12.05.2020    source แหล่งที่มา


คำตอบ (3)


หลังจากผ่าน repo ของคุณแล้ว นี่คือรหัสสุดท้าย

@WebMvcTest(HomeController.class)
class HomeControllerTest {

@Autowired
private MockMvc mvc;

@MockBean
private CustomerService customerService;

@MockBean
private PropertyService propertyService;

@MockBean
private EntityToDtoMapper mapper;


@Test
public void testaddCustomer() throws Exception {
    String uri = "/customer";
    CustomerDto custDto = this.mockCustomerObject();
    Customer customer = getCustomerEntity();
    Mockito.when(mapper.mapToEntity(Mockito.any(CustomerDto.class))).thenReturn(customer);
    String actualResult = mvc
            .perform(MockMvcRequestBuilders.post(uri).contentType(MediaType.APPLICATION_JSON)
                    .content(asJsonString(custDto)))
            .andExpect(MockMvcResultMatchers.status().isOk()).andReturn().getResponse().getContentAsString();
    Assertions.assertEquals(actualResult, "Customer with " + custDto.getId() + " sucessfully added");
}

private CustomerDto mockCustomerObject() {
    CustomerDto cusDto = new CustomerDto();
    AddressDto addressDto = new AddressDto();
    addressDto.setCity("BBSR");
    addressDto.setCountry("INDIA");
    cusDto.setDate(new Date());
    cusDto.setFirstName("Biprojeet");
    cusDto.setLastName("KAR");
    cusDto.setGender("M");
    cusDto.setAuthId(" 6AE-BH3-24F-67FG-76G-345G-AGF6H");
    cusDto.setAddressdto(addressDto);
    return cusDto;

}


private Customer getCustomerEntity() {
    Customer customer = new Customer();
    Address address = new Address();
    address.setCity("BBSR");
    address.setCountry("INDIA");
    customer.setDate(new Date());
    customer.setFirstName("Biprojeet");
    customer.setLastName("KAR");
    customer.setGender("M");
    customer.setAddress(address);
    return customer;

}

public static String asJsonString(CustomerDto cusDto) {
    try {
        return new ObjectMapper().writeValueAsString(cusDto);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

}

ปัญหาตรงนี้ที่คุณกำลังผสมแนวคิด ในการใช้งานของคุณ คุณกำลังพยายามทำการทดสอบหน่วยแต่คาดหวังว่าจะมีพฤติกรรมของการบูรณาการ

ในขณะที่คุณใช้ Spring boot กับชุดทดสอบเริ่มต้นที่มาพร้อมกับการพึ่งพาของเฟรมเวิร์กเช่น JUnit และ Mockito คุณสามารถจำลองคลาสและวิธีการเหล่านั้นซึ่งส่งข้อยกเว้นตัวชี้ Null ได้อย่างง่ายดายโดยใช้เฟรมเวิร์ก mockitio เนื่องจากเซิร์ฟเวอร์ไม่ทำงานและคอนเทนเนอร์ IOC อยู่ ไม่ขึ้นนั่นคือสาเหตุที่สิ่งเหล่านั้นเป็นโมฆะ

ดังนั้นในรหัสของคุณ CustomerService, PropertyService และ EntityToDtoMapper จึงเป็น NULL

คำถามตรงนี้คือเราจะอัปโหลดบริบทแอปพลิเคชัน Spring โดยไม่ต้องสตาร์ทเซิร์ฟเวอร์ได้อย่างไร

สามารถทำได้สองวิธีในการโหลดบริบทแอปพลิเคชันสปริงทั้งหมดโดยใช้คำอธิบายประกอบ @SpringBootTest และ @AutoConfigureMockMvc

หรือเราสามารถจำกัดบริบทของแอปพลิเคชันสปริงให้แคบลงสำหรับคอนโทรลเลอร์เท่านั้นโดยใช้คำอธิบายประกอบ @WebMvcTest

ดังนั้นวิธีแก้ปัญหาที่ฉันใช้ตรงนี้คือจำกัดการทดสอบให้แคบลงเฉพาะคอนโทรลเลอร์โดยใช้คำอธิบายประกอบ @WebMvcTest(HomeController.class) เท่านั้น

แต่ CustomerService, PropertyService และ EntityToDtoMapper เหล่านั้นยังคงเป็น NULL ดังนั้นเพื่อเยาะเย้ยคลาสเหล่านั้น เราสามารถใช้คำอธิบายประกอบ @Mock หรือ @MockBean ได้ แต่มีความแตกต่างเล็กน้อยระหว่างคำอธิบายประกอบเหล่านั้น

เมธอด Mockito.mock() ช่วยให้เราสามารถสร้างวัตถุจำลองของคลาสหรืออินเทอร์เฟซและ @MockBean เพื่อเพิ่มวัตถุจำลองให้กับบริบทของแอปพลิเคชัน Spring การเยาะเย้ยจะแทนที่ bean ที่มีอยู่ประเภทเดียวกันในบริบทของแอปพลิเคชัน

เนื่องจากเราได้อัปโหลดบริบทแอปพลิเคชัน Spring สำหรับคอนโทรลเลอร์ ดังนั้นคอนโทรลเลอร์จึงคาดหวัง bean เหล่านั้นในบริบทของแอปพลิเคชันเช่นกัน ซึ่งสามารถทำได้โดยใช้คำอธิบายประกอบ @MockBean

หลังจากเยาะเย้ย bean เหล่านั้นทั้งหมด bean controller ของคุณจะถูกสร้างขึ้น แต่มีวิธีการที่คุณคาดหวังค่าส่งคืนบางค่า ดังนั้นคุณต้องเขียนโค้ดค่าส่งคืนที่คาดหวังในโค้ดของคุณซึ่งสามารถทำได้เช่นนั้น

Mockito.when(mapper.mapToEntity(Mockito.any(CustomerDto.class))).thenReturn(customer);

หากคุณพลาดขั้นตอนนี้ในคอนโทรลเลอร์คุณจะได้รับข้อยกเว้นตัวชี้ NULL ในบรรทัดโค้ดนี้

message = "Customer with " + customer.getId() + " sucessfully added";

เพราะคุณเขียนโค้ด

Customer customer = mapper.mapToEntity(customerDto);

จะกลับมาเป็นโมฆะ

ฉันหวังว่าสิ่งนี้จะช่วยและกระตุ้นให้คุณรับความรู้เพิ่มเติมเกี่ยวกับแนวคิดเหล่านั้น

โปรดแจ้งให้เราทราบหากต้องการความช่วยเหลือเพิ่มเติม

person Anurag Srivastava    schedule 12.05.2020
comment
ใช่ นั่นอาจเป็นปัญหาที่แอปของฉันไม่สามารถใช้งานได้ แต่มันไม่ทำงาน ฉันได้รับข้อผิดพลาดเดียวกัน แอปพลิเคชันของฉันใช้งานได้แล้ว และฉันเพิ่มคำอธิบายประกอบ @Mock -- ใช้งานไม่ได้ แอพของฉันไม่อัป+เพิ่มคำอธิบายประกอบ @Mock - ใช้งานไม่ได้ - person Arpan Banerjee; 12.05.2020
comment
ยังรับ 500 อยู่มั้ย? - person Anurag Srivastava; 12.05.2020
comment
ถ้าใช่ จะต้องมาจากคลาส PropertyService ที่คุณมี Autowired Environment ดังนั้นคุณต้องล้อเลียนคลาส Environment ด้วยเช่นกัน แต่ในสถานการณ์จริง นี่คือการทดสอบการรวมระบบ ไม่ใช่การทดสอบหน่วย เพราะที่นี่คุณเข้าถึงเลเยอร์ทั้งสามชั้น ได้แก่ ตัวควบคุม บริการ และเลเยอร์การคงอยู่ - person Anurag Srivastava; 12.05.2020
comment
@Mock private PropertyService propertyService; @Mock private Environment env; ยังไม่ได้ผล :( - person Arpan Banerjee; 12.05.2020
comment
ถ้าฉันใช้ @SpringBootTest เหนือคลาสทดสอบของฉัน ก็แสดงว่ามีข้อผิดพลาดเดียวกัน PropertyService คือ null กรุณาช่วยฉันออกไป. ลองสร้างปัญหาขึ้นใหม่ในท้องถิ่นของคุณหากคุณมีเวลาว่าง - person Arpan Banerjee; 12.05.2020
comment
คุณช่วยกรุณาแบ่งปันรหัสหรือ repo ของคุณ เพื่อที่ฉันจะได้ตรวจสอบปัญหาในพื้นที่ของฉัน - person Anurag Srivastava; 13.05.2020
comment
แน่นอนว่า นี่คือซอร์สโค้ด-- [github.com/Arpan619Banerjee/SpringBoot_rest_api ] - person Arpan Banerjee; 13.05.2020
comment
ขออภัย Arpan ฉันไม่สามารถจัดการโค้ดได้ทั้งหมดเนื่องจากตารางงานที่ยุ่งและจำเป็นต้องมีการตั้งค่า DB เล็กน้อยซึ่งฉันไม่มีในเครื่องของฉันตามความต้องการของโครงการ .... แต่แน่นอนว่าฉันจะตั้งค่านั้น เร็วๆ นี้ ในระหว่างนี้ คุณช่วยบอกฉันหน่อยได้ไหมว่าคุณกำลังทำการทดสอบบูรณาการหรือการทดสอบหน่วย และคุณช่วยกรุณาระบุบันทึกข้อผิดพลาดของคุณหลังจากเยาะเย้ย PropertyService แล้ว - person Anurag Srivastava; 14.05.2020
comment
ไม่เป็นไร. มีการกล่าวถึงข้อผิดพลาดที่ฉันได้รับหลังจากการเยาะเย้ยในความคิดเห็นของคำตอบอื่น - person Arpan Banerjee; 14.05.2020
comment
Arpan ฉันได้อัปเดตโซลูชันแล้ว โปรดดำเนินการต่อไป - person Anurag Srivastava; 16.05.2020
comment
ขอบคุณ! โซลูชันการอัปเดตใช้งานได้อย่างมีเสน่ห์! ยังคงมีข้อสงสัยอยู่ประการหนึ่ง - ฉันยังคงไม่สามารถเข้าถึงบริการ prop ในคลาสทดสอบของฉันได้ แต่โซลูชันของคุณยังฮาร์ดโค้ดค่าของ authKey ด้วย ฉันพยายามรับมันจาก PropertyService แต่ได้รับข้อผิดพลาด--- ฉันสามารถใช้ชีวิตได้ด้วยการเข้ารหัสแบบฮาร์ดโค้ดในคลาสทดสอบ ดังนั้น นี้ไม่ใช่ imp หากคุณต้องการและมีเวลาว่าง คุณสามารถตรวจสอบปัญหานี้ได้ .... - person Arpan Banerjee; 16.05.2020
comment
` ModelAndView: ดูชื่อ = null ดู = null รุ่น = null FlashMap: คุณลักษณะ = null MockHttpServletResponse: สถานะ = 500 ข้อความแสดงข้อผิดพลาด = null ส่วนหัว = [ประเภทเนื้อหา: ข้อความ / ธรรมดา; charset = UTF-8, ความยาวเนื้อหา: 34] ประเภทเนื้อหา = text/plain;charset=UTF-8 Body = ไม่สามารถเพิ่มลูกค้าได้เนื่องจาก URL ที่ส่งต่อเป็นโมฆะ = null URL ที่เปลี่ยนเส้นทาง = null คุกกี้ = []` - person Arpan Banerjee; 16.05.2020
comment
และมีข้อผิดพลาดอีกอย่างหนึ่ง นี่เป็นเรื่องสำคัญ -- กรณีทดสอบของฉันผ่านแม้ว่าฉันจะให้ ผิด authId ก็ตาม โปรดลองในพื้นที่ของคุณและแจ้งให้เราทราบหากคุณมีพฤติกรรมเดียวกัน - person Arpan Banerjee; 16.05.2020

และมีข้อผิดพลาดอีกอย่างหนึ่ง นี่เป็นเรื่องสำคัญ -- กรณีทดสอบของฉันผ่านแม้ว่าฉันจะให้ authId ผิดก็ตาม โปรดลองในพื้นที่ของคุณและแจ้งให้เราทราบหากคุณมีพฤติกรรมเดียวกัน

นอกหลักสูตรการทดสอบของคุณจะถูกส่งผ่านเนื่องจากโค้ดของคุณกำลังตรวจสอบเงื่อนไขเท่านั้น ซึ่งไม่ได้ป้องกันโค้ดที่จะถูกดำเนินการ โปรดดูโค้ดของคุณด้านล่าง:

try {
        if ((!customerDto.getAuthId().equals(propertyService.getKeytoAddCustomer()))) {
            System.out.println("If check failed: "+propertyService.getKeytoAddCustomer());
            System.out.println("Unauthorized access attempted");
            message = "Unauthorized access attempted";
            finalMessage = new ResponseEntity<>(message, HttpStatus.UNAUTHORIZED);
        }
        System.out.println("If check passed :"+propertyService.getKeytoAddCustomer());

        Customer customer = mapper.mapToEntity(customerDto);
        customerService.addCustomer(customer);
        message = "Customer with " + customer.getId() + " sucessfully added";
        finalMessage = new ResponseEntity<>(message, HttpStatus.OK);

    }

ตรงนี้ภายใต้เงื่อนไข if คุณกำลังดำเนินการบล็อกของโค้ดเท่านั้น จากนั้นได้รับคำสั่งให้ดำเนินการบล็อกของโค้ดที่อยู่นอกเงื่อนไข if

ดังนั้นภายใต้เงื่อนไขที่ว่ามันไม่ทำอะไรเลย ดังนั้นคุณต้องปรับปรุงโค้ดของคุณตามพฤติกรรมที่คุณคาดหวัง

หากคุณต้องการป้องกันการเรียกใช้โค้ดของคุณ โปรดอ้างอิงโค้ดด้านล่าง

try {
        if ((!customerDto.getAuthId().equals(propertyService.getKeytoAddCustomer()))) {
            System.out.println("If check failed: "+propertyService.getKeytoAddCustomer());
            System.out.println("Unauthorized access attempted");
            message = "Unauthorized access attempted";
            return new ResponseEntity<>(message, HttpStatus.UNAUTHORIZED);
        }
        System.out.println("If check passed :"+propertyService.getKeytoAddCustomer());

        Customer customer = mapper.mapToEntity(customerDto);
        customerService.addCustomer(customer);
        message = "Customer with " + customer.getId() + " sucessfully added";
        finalMessage = new ResponseEntity<>(message, HttpStatus.OK);

    } catch (Exception e) {
        message = "Failed to add customer due to " + e.getMessage();
        e.printStackTrace();
        finalMessage = new ResponseEntity<>(message, HttpStatus.INTERNAL_SERVER_ERROR);
    }

ที่นี่ฉันได้ตั้งค่าคำสั่ง return ภายใต้เงื่อนไข If

แต่ถ้าคุณต้องการล้มเหลวในกรณีทดสอบปัจจุบันที่คุณเปรียบเทียบข้อความ โปรดดูโค้ดด้านล่าง:

try {
        if ((!customerDto.getAuthId().equals(propertyService.getKeytoAddCustomer()))) {
            System.out.println("If check failed: "+propertyService.getKeytoAddCustomer());
            System.out.println("Unauthorized access attempted");
            message = "Unauthorized access attempted";
            finalMessage = new ResponseEntity<>(message, HttpStatus.UNAUTHORIZED);
        }else {
            System.out.println("If check passed :" + propertyService.getKeytoAddCustomer());

            Customer customer = mapper.mapToEntity(customerDto);
            customerService.addCustomer(customer);
            message = "Customer with " + customer.getId() + " sucessfully added";
            finalMessage = new ResponseEntity<>(message, HttpStatus.OK);
        }

    } catch (Exception e) {
        message = "Failed to add customer due to " + e.getMessage();
        e.printStackTrace();
        finalMessage = new ResponseEntity<>(message, HttpStatus.INTERNAL_SERVER_ERROR);
    }

ที่นี่คุณเพียงแค่ต้องตั้งค่าบล็อกของโค้ดที่อยู่นอกเงื่อนไข if ใต้ส่วน else

person Anurag Srivastava    schedule 16.05.2020
comment
ใช่ นั่นเป็นความผิดพลาดโง่ๆ ของฉัน ฉันลืมคำสั่ง return แต่ตอนนี้ มันกลับมาที่จุด 0 แล้ว ตอนนี้หลังจากเพิ่มคำสั่ง return หลัง if-check(ur If you would like to prevent your code execution then please refer the code below example code) คลาสทดสอบส่งคืนสถานะ 401 uauthorized เสมอ หลังจากการดีบัก ฉันสังเกตเห็นว่า athKey ใน HomeController เป็นโมฆะ เหมือนเมื่อก่อน คุณได้ลองสิ่งนี้ในท้องถิ่นของคุณแล้วหรือยัง? รอคอยที่จะตอบกลับของคุณ! - person Arpan Banerjee; 16.05.2020
comment
สวัสดี...คุณได้มีโอกาสลองใช้สิ่งนี้หรือไม่? - person Arpan Banerjee; 19.05.2020

ลองเยาะเย้ย PropertyService ด้วย @MockBean หรือ @Mock

ฉันสังเกตเห็นว่าคุณขาด @WebMvcTest(Controller.class) เหนือคำจำกัดความของคลาสที่คุณต้องการสำหรับการทดสอบหน่วย Mvc Controllers คำอธิบาย

ถ้า @MockBean ไม่ทำงาน

พยายาม:

เมื่อใช้ Mockito.when() คุณสามารถส่งคืนผลลัพธ์ที่ต้องการ/คาดหวังและเมื่อมีการเรียกใช้วิธีที่ต้องการได้

ใช้ Mockito.verify() เพื่อให้แน่ใจว่าความปรารถนาจะถูกดำเนินการเมื่อใด

when(propertyService.getKeytoAddCustomer()).thenReturn("Desired String");

when(customerService.addCustomer(customerObject)).thenReturn("Desired result");

//DO mvc.perform(...);

verify(propertyService).getKeytoAddCustomer();

verify(customerService).addCustomer(customerObject());

ปัญหาที่สอง

ปัญหาเกี่ยวกับไฟล์คุณสมบัติที่ฉันถือว่าเป็นเพราะคุณใช้ spring.profile.active=dev แต่ไฟล์คุณสมบัติคือ test/resources คือ application.properties แทนที่จะเป็น application-dev.properties แม้ว่าจะเป็นไฟล์คุณสมบัติเดียวในการทดสอบ/ทรัพยากรก็ตาม เปลี่ยนชื่อไฟล์เหมือนกันทุกประการในโฟลเดอร์ทรัพยากรทั้งสองและดูว่าเกิดอะไรขึ้น

person Tony    schedule 12.05.2020
comment
วิธีแก้ไขปัญหาที่ 2 ใช้งานไม่ได้ ยังคงฮาร์ดโค้ดค่าไว้ แต่หลังจากเพิ่ม @WebMvcTest(HomeController.class) ฉันได้รับข้อผิดพลาดนี้---Description: Field propertyService in com.spring.liquibase.demo.controller.HomeController required a bean of type 'com.spring.liquibase.demo.utility.PropertyService' that could not be found. The injection point has the following annotations: - @org.springframework.beans.factory.annotation.Autowired(required=true) Action: Consider defining a bean of type 'com.spring.liquibase.demo.utility.PropertyService' in your configuration. - person Arpan Banerjee; 12.05.2020
comment
ถ้าฉันใช้ @SpringBootTest เหนือคลาสทดสอบของฉัน ก็แสดงว่ามีข้อผิดพลาดเดียวกัน PropertyService จะเป็นโมฆะ - person Arpan Banerjee; 12.05.2020
comment
อย่าใช้ @SpringBootTest ใช้ @RunWith(SpringRunner.class) แทน คุณได้กำหนด @MockBean PropertyService propertyService; เช่นนั้นหรือไม่? - person Tony; 12.05.2020
comment
ฉันใช้ jUnit5 ดังนั้น @RunWith จึงถูกแทนที่ด้วย @ExtendWith(SpringExtension.class) ฉันกำลังใช้สิ่งนี้ - person Arpan Banerjee; 12.05.2020