I've tried this a few times in the past with varying levels of success.
As Steve has said, you can make main() a thin wrapper around your actual code, which is a good idea anyway. The only problem with this is that it's possible to miss something that you don't find until you go to production. This actually happened to me as I forgot to instantiate the run loop, but the ROI of covering that with a test wasn't worth it and it's the kind of mistake that only happens once.
I've also done what Matteo has said and used a script to start the server, but I made this part of the build system itself (I use Gradle so this was trivial) and had a single, simple end-to-end test to verify bootstrapping etc. Every other "end to end" test was driven by the code the main() method was instantiating. Moving forward I think this is an approach I'd use again as it "felt" better and allowed me to drive out the main() method with a test instead of it just magically appearing.
One thing to think about is how you will /cleanly/ shut down your server - are you trapping the kill signal or will it be more explicit, like a shutdown port? Is this the tests way of telling you that you're missing some functionality?
I'd also agree with Steve with keeping your application lightweight. Lately I've been actively /trying/ to drive more tests end-to-end (I'll be talking at JAX London later in the year on this subject) and keeping app startup time as fast as possible. This has the advantage, or disadvantage depending on your point of view, that heavyweight frameworks like Spring and Hibernate become a no-go area as they increase startup time too much.