How to configure unit test name/description on VSTS? - c#

I have a solution that contains a unit test project. I'm using NUnit v3.10.1 and NUnit3TestAdapter v3.10.0.
Is there a way to configure how the test names are displayed in Visual Studio Team Services (VSTS), maybe displaying the test class name? At the moment it displays only the test name:
It's hard to understand which test belongs to which class. In this case, I have at least 2 test classes that have the same test names.
Running the same tests using Reshaper's test runner it's quite easy to understand which tests belong to which classes:
I have tried settings the TestName of the TestFixture Attribute attribute or setting the Description of the Test Attribute with no luck:
[TestFixture(TestName = "MemoryCacheManagerTests_TryGetItem", TestOf = typeof(MemoryCacheManager))]
public class MemoryCacheManagerTests_TryGetItem : MemoryCacheManagerTests
{
[Test(Description = "MemoryCacheManagerTests_TryGetItem_WithInvalidCacheKey_ShouldThrowArgumentException")]
[TestCaseSource(typeof(InvalidCacheKeyTestCases))]
public void WithInvalidCacheKey_ShouldThrowArgumentException(string key)
{
// ...
}
}
So how do I configure the names of the tests on VSTS?

No, there's no way to configure it. You can submit a UserVoice item to suggest product improvements.

Related

C# Is it possible to run nunit tests inside ASP.Net?

I have a very simple question.
Is it possible to run Nunit tests inside an asp.net web app?
Here is an example project:
MyApp -> ASP.Net app (.net5)
MyTests -> Nunit Tests (.net5)
My Asp.net project (MYApp) contains all my controllers and such, with a depency on NUnit.Engine and my test project.
There is another Test project (MyTests), which is just a dummy project.
I want to be able to run in a controller, inside my web app, my tests.
Example controller:
namespace MyApp.Controllers
{
[Route("api/tests")]
[ApiController]
public class TestController: ControllerBase
{
// Some helper class to verify everything is working somehow
private class ReportListener : ITestEventListener
{
public void OnTestEvent(string report)
{
Console.WriteLine(report);
}
}
[HttpGet]
public async Task<ActionResult> Trigger()
{
try
{
using ITestEngine engine = TestEngineActivator.CreateInstance();
engine.Initialize();
engine.WorkDirectory = Path.Combine(Directory.GetCurrentDirectory(), "../","MyTests/");
// Create a simple test package - one assembly, no special settings
TestPackage package = new TestPackage(#".\bin\Debug\net5.0\MyTests.dll"); //Just for debugging and testing
// Get a runner for the test package
using ITestRunner runner = engine.GetRunner(package);
runner.Load();
// Run all the tests in the assembly
XmlNode testResult = runner.Run(listener: new ReportListener(), TestFilter.Empty);
var outputs = Enumerable.Empty<string>();
foreach (XmlNode elem in testResult.SelectNodes("//test-case/output"))
{
outputs = outputs.Append(elem.InnerText);
}
}catch(Exception e)
{
}
return Ok();
}
}
}
But unfortunately all my attemps so far have failed.
Am I missing something?
Is Nunit.Engine not made to be run in an asp.net context?
I am building all this in .NET5.0 (company policy)
If needed I can provide an example project
There could be more, but one small thing would explain the failure...
The NUnit engine defaults to running tests in a separate process, which it launches. So, assuming that your code is working correctly as written, a ProcessRunner will be created and the engine will communicate with it, telling it to run your tests.
This could fail in one of two ways:
You may not have permission to create a process.
If you succeed in creating it, the code will definitely not be running in the asp.net context. In that case, it would probably error out and terminate with very little debug information provided.
A simple fix is to add a setting to the test package, telling the engine to run the tests in process.
TestPackage package = new TestPackage(#".\bin\Debug\net5.0\MyTests.dll");
package.AddSetting("ProcessModel", "InProcess");
If you get a second error after doing this, it should at least result in a clearer message and you should be able to debug through the code.

NUnit TestFixtures do not work with RestSharp

I'm trying to use NUnit TestAttributes to create and delete a RestSharp RestClient
https://github.com/nunit/docs/wiki/TestFixture-Attribute
using NUnit.Framework;
using RestSharp;
namespace Sanitized.Sanitized.Steps
{
[TestFixture]
public class SetupAndTeardown
{
public RestClient restClient;
[SetUp]
public void Init()
{
restClient = new RestClient();
}
[TearDown]
public void Cleanup()
{
restClient = null;
}
}
}
But, I get the error Object reference not set to an instance of an object. when trying to use this in another class i.e. with my automated steps.
I don't understand this, as I thought code that's in the [SetUp] [Teardown] attributes are called at the beginning and end of the test respectively.
You created a TestFixture, which is a class that contains tests. If the fixture had any tests, then NUnit would run them and would also run the setup before each test and the teardown after each test. Since you have no tests, that isn't happening. NUnit recognizes the fixture but finds nothing to run there.
You say that you have a problem when you "use" this fixture in another class. Test fixtures are not intended to be "used" by other code. Rather, they are run by NUnit.
For a better answer about how to do what you are trying to do, we first need to know what you are trying to do. When do you want the "setup" and "teardown" to run? How often should they run? Depending on those things, I can update this answer.
Replying further to your comment... If your tests are in another class, then that class is your test fixture. Is there a reason you don't want it to be the fixture?

How do I get a reference to the application under test?

I'm using specflow with the NUnit test runner. When I write my feature file and ask specflow to generate the steps, it outputs the following code:
using System;
using TechTalk.SpecFlow;
using Xamarin.UITest.Android;
namespace UITest1
{
[Binding]
public class CategoryPagerSteps
{
[Given(#"The (.*)st category is selected")]
public void GivenTheStCategoryIsSelected(int p0)
{
ScenarioContext.Current.Pending();
}
[When(#"I swipe left")]
public void WhenISwipeLeft()
{
ScenarioContext.Current.Pending();
}
[Then(#"The (.*)nd category is selected")]
public void ThenTheNdCategoryIsSelected(int p0)
{
ScenarioContext.Current.Pending();
}
}
}
This is fine, and I understand that these are "Steps" which will be called when my cucumber file with scenarios written in Gherkin calls for them.
However, being that this is a fully-integrated UI test, I need to be able to use Xamarin.UITest.Android to click on views and such.
So I need to somehow grab the object that represents the application that is under test so I can perform UI operations on it.
Now, I can see that this object is being initialized in another auto-generated test fixture file called "Tests.cs":
using NUnit.Framework;
using Xamarin.UITest;
using Xamarin.UITest.Android;
namespace UITest1
{
[TestFixture]
public class Tests
{
AndroidApp app;
[SetUp]
public void BeforeEachTest()
{
// TODO: If the Android app being tested is included in the solution then open
// the Unit Tests window, right click Test Apps, select Add App Project
// and select the app projects that should be tested.
app = ConfigureApp
.Android
// TODO: Update this path to point to your Android app and uncomment the
// code if the app is not included in the solution.
//.ApkFile ("../../../Android/bin/Debug/UITestsAndroid.apk")
.StartApp();
}
[Test]
public void AppLaunches()
{
app.Screenshot("First screen.");
}
}
}
I can see that the property AndroidApp app is the object that I need access to, but how do I access that property from the CategoryPagerSteps code above? Tests is not static nor are any of the methods or properties. I'm nervous to simply instantiate it myself because that should probably be done by the test runner, right? One of the other auto-generated files contains a testRunner property, but it is marked private.
So every avenue I've gone down appears blocked and I feel that I'm missing something obvious.
Here's how I solved it, in case anyone else might find it useful:
Following up on the link provided by #CheeseBaron from arteksoftware, the trick is to use SpecFlow's FeatureContext.Current to hold the value. This is one of the intended uses of FeatureContext.
The reference from arteksoftware used this method, as shown in this code:
[SetUp]
public void BeforeEachTest ()
{
app = AppInitializer.StartApp (platform, iOSSimulator);
FeatureContext.Current.Add ("App", app);
//This next line is not relevant to this post.
AppInitializer.InitializeScreens (platform);
}
However, it didn't work immediately for me because the [Setup] binding would not be called as part of a specflow test. Changing the binding to the SpecFlow [BeforeFeature] binding and making the method static solved the problem.
[BeforeFeature]
public static void Before()
{
AndroidApp app;
Console.WriteLine("** [BeforeFeature]");
app = ConfigureApp
.Android
// TODO: Update this path to point to your Android app and uncomment the
// code if the app is not included in the solution.
.ApkFile(<Path to APK>)
.StartApp();
FeatureContext.Current.Add("App", app);
}
Then, in the feature code itself, the app could be extracted from the FeatureContext dictionary like so:
[Binding]
public class FeatureSteps
{
AndroidApp app;
public FeatureSteps()
{
app = FeatureContext.Current.Get<AndroidApp>("App");
}
//Code for the rest of your feature steps.
}
I imagine that the selection of one's test runner is relevant to the bindings that are used, so here's my "App.config". I'm using NUnit with a SpecFlow plugin. I didn't try it with other test runner configurations.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="specFlow" type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow" />
</configSections>
<specFlow>
<!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
<!-- For additional details on SpecFlow configuration options see http://go.specflow.org/doc-config -->
<!-- use unit test provider SpecRun+NUnit or SpecRun+MsTest for being able to execute the tests with SpecRun and another provider -->
<unitTestProvider name="NUnit" />
<plugins>
<add name="SpecRun" />
</plugins>
</specFlow>
</configuration>
The repo mentioned above https://github.com/RobGibbens/BddWithXamarinUITest last updated 2015 and things have moved on to POP architecture, which I would recommend.
Have a look here - POP architecture with SpecFlow, https://github.com/xamarin-automation-service/uitest-specflow-example
You can see there is a static class called AppManager which has the App property
There a lot of videos and blog post on this style:
https://www.youtube.com/watch?v=4VR861BWkiU
https://www.youtube.com/watch?v=i0UNQvfXZhM
https://xamarindevelopersummit.com/page-object-pattern-and-uitest-best-practicies/
https://devblogs.microsoft.com/xamarin/best-practices-tips-xamarin-uitest/

NUnit in vs2012 reusing app.config when i click "Run All Tests" on multiple project solution?

I have a visual studio 2012 solution with 2 projects projA and projB, and 2 test projects projA_test and projB_test (using NUnit). ProjA and ProjB both have their own app.config with their own appsettings key/value pairs. When I click the run all tests the projA unit-tests are ran followed by the projB unit-tests. But some of the projB unit tests are failing because of ConfigurationManager.AppSettings has only the values from the app.config from projA! Is this normal behaviour or do I have some configuration setting messed up?
Edit.
A point I forgot to mention is that TeamCity (our CI server) does not fail the tests. So my local unit-test runner seems to be doing something weird..
For each of your unit tests you can just set the values for the ConfigurationManager as such.
ConfigurationManager.AppSettings["YourKey"] = YourValue;
If you do this before you objects that require those values they will work just fine. If they values are for multiple test you can do it in the testfixture setup method.
Detailed Example
Class:
public class SomeClass
{
#region Properties
public string Value { get; private set; }
#endregion Properites
#region Constructors
public SomeClass()
{
Value = ConfigurationManager.AppSettings["DatValue"];
}
#endregion Constructors
}
Test: I know this is MSTest/FluentAssertion but concept should work the same
[TestMethod]
public void Example()
{
#region Arrange
ConfigurationManager.AppSettings["DatValue"] = "Batman";
#endregion Arrange
#region Act
var someClass = new SomeClass();
#endregion Act
#region Assert
someClass.Should().NotBeNull();
someClass.Should().BeOfType<SomeClass>();
someClass.Value.Should().BeEquivalentTo("Batman");
#endregion Assert
}
This test passes in the example I just made and has no app.config file available. A unit test shouldn't be dependent on an app.config otherwise you start creepying from unit test to integration testing.
A note that ConnectionStrings are a little different. You would add those to the ConfigurationManager as such:
ConfigurationManager.ConnectionStrings.Add(new ConnectionStringSettings("Name", "ConnectionString"));

Integration testing (plain text file to fill database)

Our team is pretty new with testing. We are using scrum for the first time.
In the first sprint we are having 1 button on the gui. Pressing the button will cause to translate the content of a text file to a database (in a new thread/task). The gui will show the task is started and will poll for the state of the task.
We know how to unit test everything by using the TDD method. But when done we have to make integration tests.
What kind of tests do wee need execute in an integration test?
Do we need to check everything in the database is filled correctly by testing different files?
(IE: relationships, specific format which is stored as varchar(xxx), etc?)
If so: This could be pretty complex right? Because you dont have 1 or 2 input parameters, but you have a whole file (the content of the file i mean!!!) which is variable to test. You could make hundreds, or maybe thousands of tests for this one button press then. Worst thing: Most of those tests (i.e. formatting) is already tested on unit tests.
Most examples on internet show more gui like tests as integration test (or are the examples below acceptance tests?):
Login with correct username and password
- Input: name + password
- Expected output: A redirect to homepage
Login with incorrect username and/or password
- Input: name and password (incorrect)
- Expected output: A warning (login failed, incorrect username or password)
Your question covers MANY areas of trying to move to a better procedure for testing and environmental building. So to start with lets just touch on integration tests.
For integration tests you want an empty database for the most part, as you are testing that given a specific set of data existing you can query that data and get the desired result.
Lets use a simple example like a UserFinder class, you want to be able to find a user within the system with a given name and get a usable model back.
public class UserFinder
{
private SomeDbContext _dbContext;
public UserFinder(SomeDbContext dbContext)
{ _dbContext = dbContext }
public User FindUser(string name)
{ _dbContext.Find<User>(new FindUserByNameQuery(_dbContext, name)); }
}
Now in the above although its a pretty rubbish class we could test that given a user in the database with the name "Tester" that when you call FindUser("Tester") you should get back that user model.
So as part of this test you would want to start by setting up the expected user in the database, then you would create your user finder giving it a real database connection, then you would query the database with the name "Tester" and prove that you get that model back.
This way you can run that test in any context, be it the IDE a build script or command line, and you will get consistant results because your test is self contained, it sets up the scenario, runs the test and validates the acceptance criteria. Then once that test is done all data should be removed, the whole point being that you set up ONLY what you need for a given test, and generally set it up ONLY within that test.
Now ideally as integration tests and acceptance tests are alot slower to run than unit tests you only really want to test things that are not covered in a unit test, however at the same time you want to make sure you only test YOUR logic, like you could easily create the test scenario above using NHibernate and all you would prove is that NHibernate works, which is not the goal for you. It is impossible for US to tell YOU what you need to test as we dont know your project or what you are trying to achieve, but you should have some idea of your applications flow of logic, and if you see any points in that flow where it connects to a database or file system or passes over some other external boundry to the application where you have business logic, you probably want to put a test scenario in.
I would say you need to limit what exactly you are testing. In my spare time I'm working on a MVC4 project with EF5 as a backend, with repositories and data services. I have tried mocking EntityFramework behavior, but it just too complex. And generally, here people agreed that mocking DB context is pretty pointless. And Microsoft does testing on that anyway, so don't bother testing yourself what is already tested by MS.
In my project I've set up test project and a testing database for that. But I don't test repositories cause they are very transparent and close to EF. I'm testing my data services by giving them real context and connection string to a testing DB.
For every test class I'm dropping the database and re-create the structure. I'm re-populating the data for every test, so tests run against same data all the time.
This is considered to be an integration test, as here I'm going through a few layers, before I hit database. And in those tests I'm picking up all the possible problems I can have with the relationships in DB and other issues with DbContext.
But that as far as I go for integration testing - my controllers (and other objects) are tested with mocked-up dependencies (I'm using Moq).
And Once I'm a bit more further with UI, i'll probably write up some tests through Selenium for web-pages.
Here is some examples from my testing project:
[TestFixture]
class ProjectDataServiceTest
{
private ProjectDataService _projectDataService;
private DatabaseSeeder _seeder;
private SiteContext _context;
[TestFixtureSetUp]
public void FixtureSetUp()
{
_context = new SiteContext(); // connection string is taken from app.config file
_seeder = new DatabaseSeeder(_context);
_seeder.InitialiseDb(); // create database structure
ProjectRepository projectRepository = new ProjectRepository(_context);
_projectDataService = new ProjectDataService(projectRepository);
}
[SetUp]
public void TestSetUp()
{
_seeder.SeedDatabase(); // put some test data from a script
}
[TearDown]
public void TestTearDown()
{
_seeder.RemoveData(); // delete everything from all the tables
}
/**************** Tests are here! ********************/
[Test]
public void CheckDatabaseConnectivity()
{
Assert.Pass();
}
[Test]
public void GetNoProjectsForUser()
{ // should return no project for this user, as nothing is assigned
var user = _seeder.Users[0];
var projects = _projectDataService.GetUserProjects(user);
Assert.IsEmpty(user.UserProjectRoles);
Assert.IsEmpty(projects);
}
[Test]
public void GetAllProjetsForUser()
{
var user = _seeder.Users[2];
var projects = (List<Project>)_projectDataService.GetUserProjects(user);
int count = user.UserProjectRoles.Count;
Assert.AreEqual(count, projects.Count);
Assert.False(projects.Contains(_seeder.Projects[0]));
}
}
Controllers are tested in a plain-vanilla unit-testing fashion:
[TestFixture]
class ProjectsControllerTest
{
private ProjectsController _projectController;
private Mock<IProjectDataService> _projectDataService;
private Mock<ICurrentUserService> _currentUserService;
[SetUp]
public void SetUp()
{
MapperConfig.SetMappings();
_projectDataService = new Mock<IProjectDataService>();
_currentUserService = new Mock<ICurrentUserService>();
_currentUserService.Setup(s => s.GetCurrentAppUser()).Returns(new AppUser());
_projectController = new ProjectsController(_projectDataService.Object, _currentUserService.Object);
}
[Test]
public void InstanceOfProjectController()
{
Assert.IsInstanceOf<ProjectsController>(_projectController);
}
[Test]
public void Index()
{
var projects = new List<Project>() { new Project() { Name = "one" }, new Project() { Name = "two" } };
_projectDataService.Setup(s => s.GetUserProjects(It.IsAny<AppUser>())).Returns(projects);
var view = _projectController.Index();
Assert.IsInstanceOf<AutoMapViewResult<List<ProjectViewModel>>>(view);
}
}
And don't forget that no automated testing can replace real-person going through the system and clicking random buttons, trying to break things. Many times unit tests lack random input from a user. And that is very hard to imitate in a machine.

Categories