Your OS needs to know where the framebuffer starts in memory, how big each pixel is (3 and 4 bytes are common, I think), how long the lines are (in bytes or pixels), and the length of any unused gap between lines. (I think the gap is uncommon.) Given those facts, it can calculate what address to write to for any pixel.
But I start testing before I have all those facts.

I store some high value into the framebuffer, either at the start or some way in, and look for it on the screen. I usually need to take my glasses off, which for me is like using a powerful magnifying glass. Sometimes I store a run of pixels or a pattern. Some graphics hardware doesn't like anything being written into the gap, but I think that's even rarer than having a gap in the first place. And you can always try shorter runs at different start addresses. It's all easier if you really know the layout of your framebuffer in advance.
One of my tests was to write a pattern without regard for line length or pixel format. The pattern used 8 pixels to represent a byte, storing 255 (or was it 0xffff_ffff?) for a 1 bit and 0 for a 0 bit, as the byte counted up from 0 to 255. From looking at that, I was able to see a few things such as that the visual area didn't start at the start of the framebuffer region in my laptop, the length of lines, and that there was no gap. It was hard to see the pixels though.
I suggest testing in some highcolor or truecolor mode because you don't have to consider a palette; the values you write correspond directly to colors.
Testing the framebuffer merged right into drawing as I wrote a pixel-plotting routine to calculate the address of a pixel and set it. It was rather slow, so after some more testing with it, I wrote solid-box code starting with a `hline` function. hline took the x coord of the left end of the line, the y coord, and a length. it converted the length into a right-end x coord and clipped to the line length, then filled the length with a fast memory fill, if I remember right. The box routine clipped the y coords to the framebuffer and called hline in a loop.
And that was as far as I got.

If I'd gone further, it would have been to change the clipping code to clip to some values from a supplied struct, useful for clipping to a window and for different framebuffer sizes. A lot of things would have been changed from hard-coded to variable at this stage.
The next steps would have been copying part of an image (with clipping) using similar functions to hline and its box wrapper. That could be the foundation for text, though it would be better to go one step further, expanding an image from 1-bit or 4-bit depth to the framebuffer's depth and applying a color as it's copied. That would be the foundation for full bitmap-font support, with 4-bit for antialiased bitmap fonts. And that's as far as my
plans got.
I hope that's helpful!