I'm working in C# and I have a custom "settings" object in my software that's saved on disk that I need 开发者_StackOverflow中文版to be able to test when I upgrade versions of my software.
For example, if I have software with "version A" and have settings from that version, when I upgrade to "version B" of my software, I want to make sure that "settings A" can be upgraded cleanly.
When later I upgrade to "version C" of my software, I have to test the upgrade paths from A->C as well as B->C (version n+1 requires n+1 more test cases than version n did).
A large concern I have is that this exponential growth of testing paths will quickly get hard to maintain.
Is there a standard way of dealing with this?
Some important issues I have are:
The settings aren't necessarily stored on a local computer, so the software I inherited needs to be able to transfer these settings from computer to computer.
MSDN says they constructs like ClickOnce settings don't support this directly, and I must "develop [my] own custom settings classes for storing settings on a remote computer."
I added a comment about possibly doing this when the application first runs after an upgrade.
It isn't clear to me if your concern is with having to develop all these upgrade paths or with getting this integrated into your installation/upgrade procedure.
If the issue is with how to build and test increasingly numerous settings upgrades, then a simple, relatively easy way to do it is this:
public interface ISettingsUpgrader
{
void UpgradeSettings();
}
public abstract class SettingsUpgrader : SettingsUpgrader
{
protected int version;
public virtual void UpgradeSettings()
{
// load settings and read version info
version = settingsVersion;
}
}
public class SettingsUpgraderV2 : SettingsUpgrader
{
public override void UpgradeSettings()
{
base.UpgradeSettings();
if(version > 1) return;
// do the v1 -> v2 upgrade
}
}
public class SettingsUpgraderV3 : SettingsUpgraderV2
{
public override void UpgradeSettings()
{
base.UpgradeSettings();
if(version > 2) return;
// do the v2 -> v3 upgrade
}
}
So, for each new version, you only have to follow this convention and implement the upgrade from the previous version. All of the basic settings file handling goes in the base, abstract class, and successive upgrades will be performed as necessary.
Testing-wise, each new version requires only verifying (1) that the base method is called -- the functionality of which is already covered by existing tests, and (2) that the latest v(n-1) -> v(n) is properly executed.
As an additional note, it is probably good form to also implement a settings rollback procedure at each level, unless you're disallowing the option to roll back to a previous version.
Installers must generally be run using Administrator permissions, and therefore usually have access to the network. All you should need to do is access the current version's app config (or a registry key if you did it that way) and get the file location, then use a FileStream to pull it across, whether that's from the local comp, the local server, or a corporate server, as long as you can do it over the LAN/WAN. Pulls from an Internet address will require a different mechanism.
What I would do is layer the conversions. To convert a settings file from A to D, first convert it to B, then to C, and THEN to D. This may sound non-performant, but it will only be so in cases where the user has an extremely outdated version of the software; regular updates from the previous version will only need to go through one layer. It also has the extreme advantage of making each layer closed to change; once you have code to correctly turn version A into version B, you NEVER have to go back in and possibly break it to add the version C update logic.
The best way to deal with upgrades is to do it one step at a time.
Taking your example: Build an upgrade path from A to B, then one from B to C.
When testing an upgrade from A to C you have to run A to B first, then B to C.
This will limit testing scenarios quite a bit. A lot of software I've seen does the upgrade this way. It might result in things like having a field added to a table (upgrade to B) only to have it removed immediately (upgrade to C); but that's a small price to pay in order to limit the scenarios down.
At the end of this you only have to build an upgrade script to take you from the immediate previous version to the current one.
精彩评论