nspec / NSpec

A battle hardened testing framework for C# that's heavily inspired by Mocha and RSpec.
http://nspec.org/
MIT License
260 stars 57 forks source link

Continuous Runner similar to karma #203

Open dhilgarth opened 6 years ago

dhilgarth commented 6 years ago

I have created a simple continuous runner similar to karma: Whenever the test assembly is recompiled, the tests are re-executed. If the HTML formatter is specified, the runner opens the HTML file in a web browser and automatically reloads it on a new build.

Is this interesting to the community? I have more ideas for the runner like making the contexts and specs clickable to navigate to the source code in VS.

dhilgarth commented 6 years ago

The repo: https://github.com/dhilgarth/NSpec.ContinuousRunner/tree/develop

BrainCrumbz commented 6 years ago

I'd say @amirrajan would like that, but let's wait for his answer too

amirrajan commented 6 years ago

Here's what I've used for the past few years. Basically this detects changes and then fires of rake scripts:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace SyncDeploy
{
    class Program
    {
        static string path = null; 
        static FileSystemWatcher watcher;
        static string[] fileBlackList = new []
        {
            "#",
            "g.cs",
            "0.cs",
            "g.i.cs"
        };
            static string[] fileExtensionsWhiteList = new string[]
        {
          ".cs",
          ".coffee",
          ".rb",
          ".html",
          ".cshtml",
          ".js",
          ".css",
          ".fs",
          ".bat"
        };
        static void Main(string[] args)
        {
            path = Directory.GetCurrentDirectory();
            watcher = new FileSystemWatcher(path, "*.*");
            watcher.IncludeSubdirectories = true;
            watcher.EnableRaisingEvents = true;
            watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
            watcher.Changed += new FileSystemEventHandler(watcher_Changed);
            watcher.Created += new FileSystemEventHandler(watcher_Changed);
            watcher.Renamed += watcher_Renamed;
            Console.WriteLine("Watching for changes to the following file types: " + string.Join(", ", fileExtensionsWhiteList));
            Console.WriteLine("Watching " + path + " for changes, press Enter to stop...");
            Shell("tutorial");
            Console.ReadLine();
        }

        static void Shell(params string[] args)
        {
            ProcessStartInfo processStartInfo = new ProcessStartInfo("ruby", ".watch " + string.Join(" ", args));
            processStartInfo.UseShellExecute = false;
            processStartInfo.ErrorDialog = false;
            processStartInfo.RedirectStandardError = true;
            processStartInfo.RedirectStandardInput = true;
            processStartInfo.RedirectStandardOutput = true;
            Process process = new Process();
            process.EnableRaisingEvents = true;
            process.StartInfo = processStartInfo;
            process.OutputDataReceived += (sender, args1) => System.Console.WriteLine(args1.Data);
            process.ErrorDataReceived += (sender, args2) => System.Console.WriteLine(args2.Data);

            bool processStarted = process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();

            process.WaitForExit();
            System.Console.WriteLine("---");
        }

        static void watcher_Renamed(object source, RenamedEventArgs e)
        {
            CallWatcher(e.FullPath);
        }

        static void watcher_Changed(object sender, FileSystemEventArgs e)
        {
            CallWatcher(e.FullPath);
        }

        static void CallWatcher(string path)
        {
            foreach(var p in fileBlackList)
            {
                if(path.Contains(p)) return;
            }

            if (fileExtensionsWhiteList.Contains(Path.GetExtension(path)) && System.IO.File.Exists(path))
            {
                watcher.EnableRaisingEvents = false;
                var relativeFile = path.Replace(Directory.GetCurrentDirectory(), "");
                System.Console.WriteLine("Changed: " + relativeFile);
                Shell("file_changed", relativeFile);
                watcher.EnableRaisingEvents = true;
            }
        }
    }
}
amirrajan commented 6 years ago

Aside: I'm a glutton for low-fi solutions. CLI and terminal all the things.

With regards to running a context by clicking, I'd (personally), prefer some file watcher keep track of how a file has changed and execute "applicable" tests as needed (maybe parsing out a file using Roslyn).

johnhamm commented 6 years ago

@dhilgarth - this looks very cool! Going to set it up. Wondering if you had plans to only rerun the tests that were changed somehow (I believe SpecWatchr did this?)

dhilgarth commented 6 years ago

@johnhamm no such plans currently as this is really not that trivial. You wouldn't just need to monitor the tests but also the code they test. This is something that NCrunch does really nice, but I don't see myself having the time to implement something like that

johnhamm commented 6 years ago

Nice job though! I particularly like the HTMLSpecFormatter in action. I tried running it inside Visual Studio in the "Web Browser" window so I could embed it like my Test Explorer, but it doesn't seem to work when viewed this way. That's minor though as I just have it running on a second monitor.

johnhamm commented 6 years ago

Does anyone know if nspec works with NCrunch? I want to try that out.

dhilgarth commented 6 years ago

No, it doesn't work and you already found the respective user voice entry.

dhilgarth commented 6 years ago

Regarding the embedding and other features / issues: Please don't hesitate to open issues in the repository.