If there is such a requirement, when a user logs in, I need to verify the user name and password, and then write the user name into the log.
Public class MyLogin {public bool Valid (string userName, string passWord) {var isValid = userName = "admin" & passWord = "123456"; WriteLog (userName ); return isValid;} private void WriteLog (string message ){//.... writing to database or file }}
In the code above, if we find that the WriteLog method depends on files or databases during unit testing, the test will be more difficult. First, we need to release the dependency before testing. The Code is as follows:
public class MyLogin { public ILog Log { get; set; } public bool Valid(string userName, string passWord) { var isValid = userName == "admin" && passWord == "123456"; Log.Write(userName); return isValid; } } public interface ILog { void Write(string message); }
At this time, we introduced the ILog interface. before calling the Valid method, we need to assign values to the logs. Here, we remove the dependencies between objects. We started to write unit tests. During the tests, we needed to simulate a pile object.
Here I chose the NUnit framework for testing the framework. The test code is as follows:
[TestFixture] public class MyLoginTest { [Test] public void Vaild_Test() { MyLogin login = new MyLogin(); login.Log = new TestLog(); var isLogin = login.Valid("admin", "123456"); Assert.AreEqual(isLogin, true); } } public class TestLog : ILog { public void Write(string message) { //nothing } }
Here I have defined a class TestLog. The object generated by this class is a pile object. The purpose of the pile object is to replace the dependencies in the test. Sometimes, dependencies may need files or some configurations, which makes it difficult to test. Therefore, to facilitate the test, we use a pile object.
In the above example, the dependency between objects is removed through the interface, and the interface is assigned a value through the attribute. If the attribute is not used, we can also assign values to interfaces using other methods.
public MyLogin(ILog log) Log = log;
During the test, when initializing the Mylgoin object, pass the pile object to the constructor.
2. assign values in the factory mode.
The factory class is used to generate ILog objects, and the factory class must allow the input of ILog objects. The Code is as follows:
public class MyLogin { public bool Valid(string userName, string passWord) { var isValid = userName == "admin" && passWord == "123456"; var log = Factory.CreateLog(); log.Write(userName); return isValid; } } public interface ILog { void Write(string message); } public class Factory { private static ILog iLog; public static ILog CreateLog() { return iLog; } public static void SetLog(ILog log) { iLog = log; } }
In the test class, values must be assigned to the SetLog method of the Factory, and other operations remain unchanged.
3. Use a virtual method or an IOC container.
These operations need to be used according to the actual situation. Do not change your design (over-Test) because of testing, unless your design cannot be tested.
Conclusion: unit testing is an important task for developers. It will make your code structure clearer and make the code more readable. The next section describes how to use a framework for testing. After all, it takes a lot of time to write a pile object.