It depends on your goals the how exhaustively you want to test.
Personally, for anything really extensive I have:
1. Tests that test the logic of individual functions / classes / methods. I think of this (rightly or wrongly) as unit testing.
2. Tests that validate the outcome of applying code to a blank machine (created via vagrant).
3. Tests that can be used to validate the code has been applied to a real host.
At the very least, unit testing to verify what you're trying to push isn't broken in some way. Syntax testing only goes so far after all. It takes time to write the tests, but that time can be reclaimed by not having to debug typographical or logic errors after you've attempted to push code.
Anything on top of that is a distinct bonus.
Not unit tests. The unit tests exist in my repos, but they don't form part of the "built" artefact. However, I might push operational validation tests with code.
The development to release process for me is something like:
1. Spawn a branch (dev) in VCS to start working on a change
2. Develop changes.
3. Develop tests (arguably this might come first, but I'm not quite up to TDD yet).
4. Execute unit tests
5. Pull to master.
6. Build server triggers on commit to master
7. Build server executes unit tests
8. Build server does everything required to package the module / resource / whatever
9. Build server pushes to the artefact to a feed (in my case, a nuget repo)
10. Clients consume code
I haven't read it, but you might find it useful.
Hopefully it doesn't entirely disagree with my approach :)
HTH
Chris