Personally, I would not like to live with static methods to keep consistency across a code base.
The advantages, whether you consider them "real" or not, of injecting the settings lie, as always in the freedom gained and the disadvantages avoided.
I'd always prefer to inject a settings instance as it ties you down the least and doesn't force you to use a mocking framework.
Mocking the static methods is the next best, I guess. As you are in C# and static and virtual don't mix there, I can't think of a convenient way - like using a test descendant and overriding the methods - to mock the methods without using a mocking framework.
Updating the database values before the test is horrible. As your tests then have an external dependency, they automatically become integration tests. It can work, but either you have to make your tests all use the same values or update the values every test method execution. The first is horribly restrictive. The latter will slow down your tests extremely and make everybody turn them off... No use having them in that case.
In short: injection prefered, use mocking the static methods as a crutch if you can't afford to update all uses of your static settings class to an injection pattern all in one go.
If I understand your setup with the settings class correctly, another option might be to keep your static class, make reading the values from the database happen as part of an initialization call on that class. Give the initialization method two parameters: one name/value pairs or whatever you like that you can pass in from your tests to populate your settings dictionary, the other to indicate whether values should be read from the database. Make the defaults to be an empty list of name/value pairs and "yes" read from db. (You may need to use overloads in C# to allow for default parameter values).
Now you also have your hands free for testing without affecting production use of the static class.
- Production code would simply call Initialize without using any parameters at some point in the startup of your application.
- Test code can call with an empty list and "no" to clear the settings.
- Test code can call with a list of name/value pairs and "no" to provide a limited set of specific values (clearing out what was there before if you so desire).
- Test code can call with a list of name/value pairs and "yes" to provide overrides to whatever will be read from the database.