2010-03-04 14 views
12

समस्यायूनिट परीक्षण से प्रोग्रामेटिक रूप से एक WPF एप्लिकेशन कैसे शुरू करें?

VS2010 और TFS2010 समर्थन तथाकथित बना कर Coded UI Tests। मेरे द्वारा प्राप्त किए गए सभी डेमो, कोड किए गए यूआई टेस्ट शुरू होने पर या बाद में पूर्ण पथ का उपयोग करके EXE प्रारंभ किया गया है, तो पृष्ठभूमि में पहले से चल रहे WPF एप्लिकेशन से शुरू करें।

मैं, हालांकि, यूनिट परीक्षण कोड से परीक्षण के तहत अपना डब्ल्यूपीएफ आवेदन शुरू करना चाहता हूं। इस तरह यह बिल्ड सर्वर और मेरे साथियों की कामकाजी प्रतियों पर भी काम करेगा।

मैं इसे कैसे पूरा करूं?

मेरे खोजों अब तक

क) इस पोस्ट how to start a XAML window को दर्शाता है। लेकिन यह वही नहीं है जो मैं चाहता हूं। मैं App.xaml शुरू करना चाहता हूं क्योंकि इसमें XAML संसाधन हैं और फ़ाइल के पीछे कोड में एप्लिकेशन तर्क है।

ख) this post पर दूसरा स्क्रीनशॉट जो धारणात्मक काफी है एक लाइन

ApplicationUnterTest calculatorWindow = ApplicationUnderTest.Launch(...); 

के साथ शुरू है कि मैं क्या करने के लिए फिर से इस उदाहरण एक निरपेक्ष पथ देख रहा हूँ, सिवाय इसके कि का उपयोग करता है निष्पादन योग्य फ़ाइल को दर्शाता है।

सी) ए Google search for "Programmatically start WPF" या तो मदद नहीं की।

उत्तर

1

मैं ApplicationUnderTest.Launch (...) (MSDN) का उपयोग, जो स्वत: जब माइक्रोसॉफ्ट टैस्ट मैनेजर के साथ एक स्वचालित परीक्षण रिकॉर्डिंग बनाई गई है समाप्त हो गया।

4
MyProject.App myApp = new MyProject.App(); 
myApp.InitializeComponent(); 
myApp.Run(); 
4

मैं VS2008 में इसी तरह के और मैन्युअल रूप से यूआई जासूस का उपयोग करके मुझे नियंत्रण और कुछ सहायक तरीकों की पहचान में मदद करने के परीक्षण बनाने के लिए कुछ कर रहा हूँ, नहीं दिखाया, बटन क्लिक गति प्रदान और स्क्रीन पर मूल्यों को सत्यापित करने के। मैं उस प्रक्रिया को लॉन्च करने के लिए प्रक्रिया ऑब्जेक्ट का उपयोग करता हूं जिसे मैं TestInitialize विधि में परीक्षण कर रहा हूं और TestCleanup विधि में प्रक्रिया को बंद करता हूं। क्लीनअप में प्रक्रिया पूरी तरह से बंद होने के लिए मेरे पास कई तरीके हैं। पूर्ण पथ समस्या के लिए, मैं केवल प्रोग्रामेटिक रूप से वर्तमान पथ को देखता हूं और अपने एप्लिकेशन के निष्पादन योग्य को जोड़ता हूं। चूंकि मुझे नहीं पता कि एप्लिकेशन को शुरू करने में कितना समय लगता है, मैंने अपनी मुख्य विंडो में ऑटोमेशन आईडी डाल दिया और इसे "UserAplicationWindow" पर सेट किया और इसके लिए प्रतीक्षा करने की प्रतीक्षा करें, बेशक, आपके पास कुछ और हो सकता है जिसके लिए आप प्रतीक्षा कर सकते हैं । अंत में, मैं बेस क्लास के रूप में MyTestClass का उपयोग करता हूं और विभिन्न परीक्षणों के लिए कक्षा का विस्तार करता हूं।

[TestClass] 
public class MyTestClass 
{ 
    private Process _userAppProcess; 
    private AutomationElement _userApplicationElement ; 

    /// <summary> 
    /// Gets the current directory where the executables are located. 
    /// </summary> 
    /// <returns>The current directory of the executables.</returns> 
    private static String GetCurrentDirectory() 
    { 
     return Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).AbsolutePath).Replace("%20", " "); 
    } 

    [TestInitialize] 
    public void SetUp() 
    { 
     Thread appThread = new Thread(delegate() 
     { 
      _userAppProcess = new Process(); 
      _userAppProcess.StartInfo.FileName =GetCurrentDirectory() + "\\UserApplication.exe"; 
      _userAppProcess.StartInfo.WorkingDirectory = DirectoryUtils.GetCurrentDirectory(); 
      _userAppProcess.StartInfo.UseShellExecute = false; 
      _userAppProcess.Start(); 
     }); 
     appThread.SetApartmentState(ApartmentState.STA); 
     appThread.Start(); 

     WaitForApplication(); 
    } 

    private void WaitForApplication() 
    { 
     AutomationElement aeDesktop = AutomationElement.RootElement; 
     if (aeDesktop == null) 
     { 
      throw new Exception("Unable to get Desktop"); 
     } 

     _userApplicationElement = null; 
     do 
     { 
      _userApplicationElement = aeDesktop.FindFirst(TreeScope.Children, 
       new PropertyCondition(AutomationElement.AutomationIdProperty, "UserApplicationWindow")); 
      Thread.Sleep(200); 
     } while ((_userApplicationElement == null || _userApplicationElement.Current.IsOffscreen)); 

    } 

    [TestCleanup] 
    public void CleanUp() 
    { 
     try 
     { 
      // Tell the application's main window to close. 
      WindowPattern window = _userApplicationElement.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern ; 
      window.Close(); 
      if (!_userAppProcess.WaitForExit(3000)) 
      { 
       // We waited 3 seconds for the User Application to close on its own. 
       // Send a close request again through the process class. 
       _userAppProcess.CloseMainWindow(); 
      } 

      // All done trying to close the window, terminate the process 
      _userAppProcess.Close(); 
      _userAppProcess = null; 
     } 
     catch (Exception ex) 
     { 
      // I know this is bad, but catching the world is better than letting it fail. 
     } 
    } 
} 
+0

धन्यवाद! मुझे WaitForAplication() भाग पसंद है। – Lernkurve

0

यहाँ क्या मैं सिर्फ एक साथ कि में इकाई परीक्षण Caliburn सूक्ष्म सफल होता है एक छोटा सा काट दिया:

[TestFixture] 
public class when_running_bootstrapper 
{ 
    [Test] 
    public void it_should_request_its_view_model() 
    { 
     TestFactory.PerformRun(b => 
      CollectionAssert.Contains(b.Requested, typeof(SampleViewModel).FullName)); 
    } 

    [Test] 
    public void it_should_request_a_window_manager_on_dotnet() 
    { 
     TestFactory.PerformRun(b => 
      CollectionAssert.Contains(b.Requested, typeof(IWindowManager).FullName)); 
    } 

    [Test] 
    public void it_should_release_the_window_manager_once() 
    { 
     TestFactory.PerformRun(b => 
      Assert.That(b.ReleasesFor<IWindowManager>(), Is.EqualTo(1))); 
    } 

    [Test] 
    public void it_should_release_the_root_view_model_once() 
    { 
     TestFactory.PerformRun(b => 
      Assert.That(b.ReleasesFor<SampleViewModel>(), Is.EqualTo(1))); 
    } 
} 

static class TestFactory 
{ 
    public static void PerformRun(Action<TestBootStrapper> testLogic) 
    { 
     var stackTrace = new StackTrace(); 
     var name = stackTrace.GetFrames().First(x => x.GetMethod().Name.StartsWith("it_should")).GetMethod().Name; 
     var tmpDomain = AppDomain.CreateDomain(name, 
      AppDomain.CurrentDomain.Evidence, 
      AppDomain.CurrentDomain.BaseDirectory, 
      AppDomain.CurrentDomain.RelativeSearchPath, 
      AppDomain.CurrentDomain.ShadowCopyFiles); 
     var proxy = (Wrapper)tmpDomain.CreateInstanceAndUnwrap(typeof (TestFactory).Assembly.FullName, typeof (Wrapper).FullName); 

     try 
     { 
      testLogic(proxy.Bootstrapper); 
     } 
     finally 
     { 
      AppDomain.Unload(tmpDomain); 
     } 
    } 
} 

[Serializable] 
public class Wrapper 
    : MarshalByRefObject 
{ 
    TestBootStrapper _bootstrapper; 

    public Wrapper() 
    { 
     var t = new Thread(() => 
      { 
       var app = new Application(); 
       _bootstrapper = new TestBootStrapper(app); 
       app.Run(); 
      }); 
     t.SetApartmentState(ApartmentState.STA); 
     t.Start(); 
     t.Join(); 
    } 

    public TestBootStrapper Bootstrapper 
    { 
     get { return _bootstrapper; } 
    } 
} 

[Serializable] 
public class TestBootStrapper 
    : Bootstrapper<SampleViewModel> 
{ 
    [NonSerialized] 
    readonly Application _application; 

    [NonSerialized] 
    readonly Dictionary<Type, object> _defaults = new Dictionary<Type, object> 
     { 
      { typeof(IWindowManager), new WindowManager() } 
     }; 

    readonly Dictionary<string, uint> _releases = new Dictionary<string, uint>(); 
    readonly List<string> _requested = new List<string>(); 

    public TestBootStrapper(Application application) 
    { 
     _application = application; 
    } 

    protected override object GetInstance(Type service, string key) 
    { 
     _requested.Add(service.FullName); 

     if (_defaults.ContainsKey(service)) 
      return _defaults[service]; 

     return new SampleViewModel(); 
    } 

    protected override void ReleaseInstance(object instance) 
    { 
     var type = instance.GetType(); 
     var t = (type.GetInterfaces().FirstOrDefault() ?? type).FullName; 

     if (!_releases.ContainsKey(t)) 
      _releases[t] = 1; 
     else 
      _releases[t] = _releases[t] + 1; 
    } 

    protected override IEnumerable<object> GetAllInstances(Type service) 
    { 
     throw new NotSupportedException("Not in this test"); 
    } 

    protected override void BuildUp(object instance) 
    { 
     throw new NotSupportedException("Not in this test"); 
    } 

    protected override void Configure() 
    { 
     base.Configure(); 
    } 

    protected override void OnExit(object sender, EventArgs e) 
    { 
     base.OnExit(sender, e); 
    } 

    protected override void OnStartup(object sender, System.Windows.StartupEventArgs e) 
    { 
     base.OnStartup(sender, e); 

     _application.Shutdown(0); 
    } 

    protected override IEnumerable<System.Reflection.Assembly> SelectAssemblies() 
    { 
     return new[] { typeof(TestBootStrapper).Assembly }; 
    } 

    public IEnumerable<string> Requested 
    { 
     get { return _requested; } 
    } 

    public uint ReleasesFor<T>() 
    { 
     if (_releases.ContainsKey(typeof(T).FullName)) 
      return _releases[typeof (T).FullName]; 
     return 0u; 
    } 
} 

[Serializable] 
public class SampleViewModel 
{ 
} 
0

यह नहीं किया जा काफी क्या आप चाहते हो सकता है, लेकिन मैं अपने WPF क्षुधा और के साथ एक समान समस्या थी उनकी कोडित यूआई परीक्षण। मेरे मामले में मैं टीएफएस बिल्ड (प्रयोगशाला टेम्पलेट के माध्यम से) का उपयोग कर रहा हूं और इसकी तैनाती हमारे निर्माण का उत्पादन लेती है; एक एमएसआई और लक्ष्य पर स्थापित करता है, परीक्षण तब स्थापित सॉफ्टवेयर के खिलाफ चलाते हैं।

अब क्योंकि हम स्थापित सॉफ्टवेयर हम परीक्षण जोड़ा खिलाफ परीक्षण करने के लिए इच्छुक रहे हैं तरीकों कि एमएसआई एपीआई बुला हमारे संस्थापक में उत्पाद/घटक GUIDs के लिए स्थापित फ़ोल्डर पाने के लिए द्वारा जीयूआई हम परीक्षण शुरू आरंभ।

यहाँ एक कोड निकालने के लिए, अपने इंस्टॉलर से अपने उत्पाद और घटक GUIDs स्थानापन्न के लिए याद)

/// <summary> 
    /// Starts the GUI. 
    /// </summary> 
    public void StartGui() 
    { 
     Console.WriteLine("Starting GUI process..."); 
     try 
     { 
      var path = this.DetectInstalledCopy(); 
      var workingDir = path; 
      var exePath = Path.Combine(path, "gui.exe"); 

      //// or ApplicationUnderTest.Launch() ??? 
      Console.Write("Starting new GUI process... "); 
      this.guiProcess = Process.Start(new ProcessStartInfo 
      { 
       WorkingDirectory = workingDir, 
       FileName = exePath, 
       LoadUserProfile = true, 
       UseShellExecute = false 
      }); 
      Console.WriteLine("started GUI process (id:{0})", this.guiProcess.Id); 
     } 
     catch (Win32Exception e) 
     { 
      this.guiProcess = null; 
      Assert.Fail("Unable to start GUI process; exception {0}", e); 
     } 
    } 

    /// <summary> 
    /// Detects the installed copy. 
    /// </summary> 
    /// <returns>The folder in which the MSI installed the GUI feature of the cortex 7 product.</returns> 
    private string DetectInstalledCopy() 
    { 
     Console.WriteLine("Looking for install directory of CORTEX 7 GUI app"); 
     int buffLen = 1024; 
     var buff = new StringBuilder(buffLen); 
     var ret = NativeMethods.MsiGetComponentPath(
      "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", // YOUR product GUID (see WiX installer) 
      "{YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY}", // The GUI Installer component GUID 
      buff, 
      ref buffLen); 

     if (ret == NativeMethods.InstallstateLocal) 
     { 
      var productInstallRoot = buff.ToString(); 
      Console.WriteLine("Found installation directory for GUI.exe feature at {0}", productInstallRoot); 
      return productInstallRoot; 
     } 

     Assert.Fail("GUI product has not been installed on this PC, or not for this user if it was installed as a per-user product"); 
     return string.Empty; 
    } 

    /// <summary> 
    /// Stops the GUI process. Initially by asking nicely, then chopping its head off if it takes too long to leave. 
    /// </summary> 
    public void StopGui() 
    { 
     if (this.guiProcess != null) 
     { 
      Console.Write("Closing GUI process (id:[{0}])... ", this.guiProcess.Id); 
      if (!this.guiProcess.HasExited) 
      { 
       this.guiProcess.CloseMainWindow(); 
       if (!this.guiProcess.WaitForExit(30.SecondsAsMilliseconds())) 
       { 
        Assert.Fail("Killing GUI process, it failed to close within 30 seconds of being asked to close"); 
        this.guiProcess.Kill(); 
       } 
       else 
       { 
        Console.WriteLine("GUI process closed gracefully"); 
       } 
      } 

      this.guiProcess.Close(); // dispose of resources, were done with the object. 
      this.guiProcess = null; 
     } 
    } 

और यहाँ एपीआई आवरण कोड है:

/// <summary> 
    /// Get the component path. 
    /// </summary> 
    /// <param name="product">The product GUI as string with {}.</param> 
    /// <param name="component">The component GUI as string with {}.</param> 
    /// <param name="pathBuf">The path buffer.</param> 
    /// <param name="buff">The buffer to receive the path (use a <see cref="StringBuilder"/>).</param> 
    /// <returns>A obscure Win32 API error code.</returns> 
    [DllImport("MSI.DLL", CharSet = CharSet.Unicode)] 
    internal static extern uint MsiGetComponentPath(
     string product, 
     string component, 
     StringBuilder pathBuf, 
     ref int buff); 
संबंधित मुद्दे