DEV Community

Jan Cizmar Subscriber for Tolgee

Posted on

4

Testing file Download โฌ‡๏ธ in Spring ๐Ÿƒ Boot

It's pretty common case to generate file on the backend and let user to download it. But how to test it? I found testing of this scenario not quite well documented. So here's my bit.

We have to use getAsyncResult method from MvcResult interface, which enables us to retrieve content provided using StreamingResponseBody. So first, let's look how to generate file in the controller.

I am going to use Kotlin btw. ๐Ÿ˜Ž

Streaming body with StreamingResponseBody

Let's say we want to enable user to download some fine, which is not very small. For the demo I will just generate a text file containing a lot of a characters.



@Controller
@RequestMapping(value = ["/api/v1/03/get-file"])
class FileProducingController {
    @GetMapping(value = [""], produces = ["application/text"])
    fun export(): ResponseEntity<StreamingResponseBody> {

        return ResponseEntity
                .ok()
                // set a filename
                .header(
                        "Content-Disposition",
                        """attachment; filename="%file.txt""""
                )
                .body(
                        // stream the body
                        StreamingResponseBody { out: OutputStream ->
                            val text = "a".repeat(1000000)
                            out.write(text.toByteArray())
                            out.close()
                        }
                )
    }
}


Enter fullscreen mode Exit fullscreen mode

So what I am doing here is that I am setting the file name, which is the default when user downloads it in a browser. And then I am writing the text to the StreamResponseBody's output.

Finally the testing part

So when I want to test it I have to do this.



@SpringBootTest
@AutoConfigureMockMvc
internal class FileProducingControllerTest {
    @field:Autowired
    lateinit var mvc: MockMvc

    @Test
    fun `produces correct body`() {
        val result = mvc.perform(
                MockMvcRequestBuilders.get("/api/v1/03/get-file")
        )
                .andDo { it.asyncResult }
                .andReturn()
        val content = result.response.contentAsString
        assertEquals("a".repeat(1000000), content)
    }
}


Enter fullscreen mode Exit fullscreen mode

Notice the part with it.asyncResult. Without this part the test would fail. There will be just part of the output in the response's contentAsString result, because it won't wait for the stream to end. You can try this by removing the part and see it fails.


Tolgee is an open-source solution for software localization. It saves developer's time. Go to Tolgee.io and have fun!

Image description

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (2)

Collapse
 
bemygreenheart profile image
bemygreenheart โ€ข

Really bad example.

Collapse
 
jancizmar profile image
Jan Cizmar โ€ข

Why so?

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

๐Ÿ‘‹ Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay