2

I'm using

and following this guide:

One thing I use frequently in python development is elpy's C-c C-t to run a single test at point.

How can I configure this to use lsp-mode instead?

Mittenchops
  • 289
  • 1
  • 8

1 Answers1

2

For my Emacs Python environment, I recently switched from Elpy to lsp-mode too. Mainly to benefit from the dap-mode debugger and a better "Find definition" functionality (able to find a definition in the virtual environement libraries). And also because the great Elpy package is not maintained anymore.

But what I was still missing from Elpy, was the ability to quickly run the tests as @Mittenchops pointed it out.

As I couldn't find any package to easily fix that, I wrote my own Elisp functions : django-run-all-tests, django-run-buffer-tests, and django-run-test-at-point (the last one inspired by the Elpy one).

These work well assuming :

  • it is a Django project (else the test runner command needs to be adapted)
  • tests are in a single directory that have to configured with django-tests-dir-name variable relatively to the project root ((setq django-tests-dir-name "tests") for example)
  • projectile package is installed (needed to retrieve project root)
;; Copy of elpy-test--current-test-name function from Elpy project
;; https://github.com/jorgenschaefer/elpy
(defun django-get-test-name-at-point ()
  "Return the name of the test at point."
  (let ((name (python-info-current-defun)))
    (if (and name (string-match "\\`\\([^.]+\\.[^.]+\\)\\." name)) (match-string 1 name) name)))

(defun django-get-module ()
  (file-name-sans-extension (buffer-name)))

(defun django-run-tests (&optional module test)
  (let* ((dir-part django-tests-dir-name)
         (module-part (if module (concat "." module) ""))
         (test-part (if test (concat "." test) ""))
         (param (concat dir-part module-part test-part))
         (command (format "./manage.py test %s --keepdb" param)))
    (message command)          
    (projectile-run-async-shell-command-in-root command)))

(defun django-run-all-tests ()
  "Run all Django api tests."
  (interactive)
  (django-run-tests))

(defun django-run-buffer-tests ()
  "Run Django api tests for current buffer."
  (interactive)
  (let ((module (django-get-module)))
    (django-run-tests module)))

(defun django-run-test-at-point ()
  "Run Django api test at point."
  (interactive)
  (let ((module (django-get-module))
        (test (django-get-test-name-at-point)))
    (django-run-tests module test)))

Put this code in your init.el file. An example using use-package package and adding some key bindings to the Python mode :

(use-package python
  :bind (:map python-mode-map (("C-c t a" . django-run-all-tests)
                               ("C-c t f" . django-run-buffer-tests)
                               ("C-c t p" . django-run-test-at-point)))
  :config
;; Past the functions here
)