Search code examples
c#.netunit-testingintegration-testingmstest

C# - MS Test - Create a test that runs another test first


In our application, I have created a login test for our website. If this test is successful then login is successful. Now to create tests for other parts of the website, I need to perform login first.

Is there a way so that all the other tests that I will create will run the login test first? For example: is it possible to create a custom login test attribute that I can put on all other test methods, so that they will run login first? But then I also need the return value from that login test !

If not, then I will have to just write a plain C# function that performs login operation and I will need to put that function call, as the first line of every test.


Solution

  • When you're writing unit tests, you are testing each method in isolation. Meaning, the method that you're testing must not, and cannot depend on anything else in order to run.

    The reason why you have a problem now, probably is because you broke at least the single responsability principle (the one that states that your class should only have one single reason to be changed). I can assume this because you are stating that your OTHER methods in a class depend on login being successful. Here's how to solve it:

    Make an interface for your login method, something like:

    public interface ILoginManager{
       void Authenticate(string username, string password);
    
       void IsAuthenticated{ get;}
    }
    

    Next, using the Dependency Inversion Principle, add this interface to your class with methods in it:

    public class MyWorkerClass
    {
      private readonly ILoginManager _loginManager;
      public MyWorkerClass(ILoginManager loginManager){
        _loginManager = loginManager;
      }
    
    
      public bool LogOnUser(string userName, string password){
        _loginManager.Authenticate(userName, password);
    
        return _loginManager.IsAuthenticated;
      }
    }
    

    Now, in all your tests, you can mock out the LoginManager, and set your expectations there, i.e.

    [TestMethod]
    public void SomeMethod_UserIsAuthenticated_InvokesSomeOtherMethod()
    {
      // Arrange
      GetMockFor<ILoginManager>().SetupGet(lm => lm.Authenticated).Returns(true);
    
      // Act
      var result = Instance.SomeMethod();
    
      // Assert
      GetMockFor<ISomeOtherInterface>()
        .Verify(o => o.SomeOtherMethod(), Times.AtLeastOnce() );
    }